diff --git a/osu.Android.props b/osu.Android.props
index 0bb0bf171c..ed2b27e1c7 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -52,6 +52,6 @@
-
+
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBarrelRoll.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBarrelRoll.cs
index b6cfa514a1..aee431284e 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBarrelRoll.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBarrelRoll.cs
@@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Bindables;
+using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Game.Configuration;
using osu.Game.Rulesets.Mods;
@@ -30,9 +31,11 @@ namespace osu.Game.Rulesets.Osu.Mods
public override string Description => "The whole playfield is on a wheel!";
public override double ScoreMultiplier => 1;
+ public override string SettingDescription => $"{SpinSpeed.Value} rpm {Direction.Value.GetDescription().ToLowerInvariant()}";
+
public void Update(Playfield playfield)
{
- playfield.Rotation = (Direction.Value == RotationDirection.CounterClockwise ? -1 : 1) * 360 * (float)(playfield.Time.Current / 60000 * SpinSpeed.Value);
+ playfield.Rotation = (Direction.Value == RotationDirection.Counterclockwise ? -1 : 1) * 360 * (float)(playfield.Time.Current / 60000 * SpinSpeed.Value);
}
public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset)
diff --git a/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs
index 7394458482..57b3687d3a 100644
--- a/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs
+++ b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs
@@ -77,7 +77,33 @@ namespace osu.Game.Tests.Gameplay
AddStep("start time", () => gameplayContainer.Start());
- AddUntilStep("sample playback succeeded", () => sample.LifetimeEnd < double.MaxValue);
+ AddUntilStep("sample played", () => sample.RequestedPlaying);
+ AddUntilStep("sample has lifetime end", () => sample.LifetimeEnd < double.MaxValue);
+ }
+
+ [Test]
+ public void TestSampleHasLifetimeEndWithInitialClockTime()
+ {
+ GameplayClockContainer gameplayContainer = null;
+ DrawableStoryboardSample sample = null;
+
+ AddStep("create container", () =>
+ {
+ var working = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
+ working.LoadTrack();
+
+ Add(gameplayContainer = new GameplayClockContainer(working, 1000, true));
+
+ gameplayContainer.Add(sample = new DrawableStoryboardSample(new StoryboardSampleInfo(string.Empty, 0, 1))
+ {
+ Clock = gameplayContainer.GameplayClock
+ });
+ });
+
+ AddStep("start time", () => gameplayContainer.Start());
+
+ AddUntilStep("sample not played", () => !sample.RequestedPlaying);
+ AddUntilStep("sample has lifetime end", () => sample.LifetimeEnd < double.MaxValue);
}
[TestCase(typeof(OsuModDoubleTime), 1.5)]
diff --git a/osu.Game.Tests/NonVisual/SessionStaticsTest.cs b/osu.Game.Tests/NonVisual/SessionStaticsTest.cs
new file mode 100644
index 0000000000..d5fd803986
--- /dev/null
+++ b/osu.Game.Tests/NonVisual/SessionStaticsTest.cs
@@ -0,0 +1,47 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using NUnit.Framework;
+using osu.Game.Configuration;
+using osu.Game.Input;
+
+namespace osu.Game.Tests.NonVisual
+{
+ [TestFixture]
+ public class SessionStaticsTest
+ {
+ private SessionStatics sessionStatics;
+ private IdleTracker sessionIdleTracker;
+
+ [SetUp]
+ public void SetUp()
+ {
+ sessionStatics = new SessionStatics();
+ sessionIdleTracker = new GameIdleTracker(1000);
+
+ sessionStatics.SetValue(Static.LoginOverlayDisplayed, true);
+ sessionStatics.SetValue(Static.MutedAudioNotificationShownOnce, true);
+ sessionStatics.SetValue(Static.LowBatteryNotificationShownOnce, true);
+ sessionStatics.SetValue(Static.LastHoverSoundPlaybackTime, (double?)1d);
+
+ sessionIdleTracker.IsIdle.BindValueChanged(e =>
+ {
+ if (e.NewValue)
+ sessionStatics.ResetValues();
+ });
+ }
+
+ [Test]
+ [Timeout(2000)]
+ public void TestSessionStaticsReset()
+ {
+ sessionIdleTracker.IsIdle.BindValueChanged(e =>
+ {
+ Assert.IsTrue(sessionStatics.GetBindable(Static.LoginOverlayDisplayed).IsDefault);
+ Assert.IsTrue(sessionStatics.GetBindable(Static.MutedAudioNotificationShownOnce).IsDefault);
+ Assert.IsTrue(sessionStatics.GetBindable(Static.LowBatteryNotificationShownOnce).IsDefault);
+ Assert.IsTrue(sessionStatics.GetBindable(Static.LastHoverSoundPlaybackTime).IsDefault);
+ });
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/Components/TestSceneIdleTracker.cs b/osu.Game.Tests/Visual/Components/TestSceneIdleTracker.cs
index 4d64c7d35d..86a9d555a3 100644
--- a/osu.Game.Tests/Visual/Components/TestSceneIdleTracker.cs
+++ b/osu.Game.Tests/Visual/Components/TestSceneIdleTracker.cs
@@ -81,6 +81,13 @@ namespace osu.Game.Tests.Visual.Components
[Test]
public void TestMovement()
{
+ checkIdleStatus(1, false);
+ checkIdleStatus(2, false);
+ checkIdleStatus(3, false);
+ checkIdleStatus(4, false);
+
+ waitForAllIdle();
+
AddStep("move to top right", () => InputManager.MoveMouseTo(box2));
checkIdleStatus(1, true);
@@ -102,6 +109,8 @@ namespace osu.Game.Tests.Visual.Components
[Test]
public void TestTimings()
{
+ waitForAllIdle();
+
AddStep("move to centre", () => InputManager.MoveMouseTo(Content));
checkIdleStatus(1, false);
@@ -140,7 +149,7 @@ namespace osu.Game.Tests.Visual.Components
private void waitForAllIdle()
{
- AddUntilStep("Wait for all idle", () => box1.IsIdle && box2.IsIdle && box3.IsIdle && box4.IsIdle);
+ AddUntilStep("wait for all idle", () => box1.IsIdle && box2.IsIdle && box3.IsIdle && box4.IsIdle);
}
private class IdleTrackingBox : CompositeDrawable
@@ -149,7 +158,7 @@ namespace osu.Game.Tests.Visual.Components
public bool IsIdle => idleTracker.IsIdle.Value;
- public IdleTrackingBox(double timeToIdle)
+ public IdleTrackingBox(int timeToIdle)
{
Box box;
@@ -158,7 +167,7 @@ namespace osu.Game.Tests.Visual.Components
InternalChildren = new Drawable[]
{
- idleTracker = new IdleTracker(timeToIdle),
+ idleTracker = new GameIdleTracker(timeToIdle),
box = new Box
{
Colour = Color4.White,
diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorClipboard.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorClipboard.cs
index 29046c82a6..01d9966736 100644
--- a/osu.Game.Tests/Visual/Editing/TestSceneEditorClipboard.cs
+++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorClipboard.cs
@@ -3,12 +3,16 @@
using System.Linq;
using NUnit.Framework;
+using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
+using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Objects;
+using osu.Game.Screens.Edit.Compose.Components;
+using osu.Game.Screens.Edit.Compose.Components.Timeline;
using osu.Game.Tests.Beatmaps;
using osuTK;
@@ -110,8 +114,9 @@ namespace osu.Game.Tests.Visual.Editing
AddAssert("duration matches", () => ((Spinner)EditorBeatmap.HitObjects.Single()).Duration == 5000);
}
- [Test]
- public void TestCopyPaste()
+ [TestCase(false)]
+ [TestCase(true)]
+ public void TestCopyPaste(bool deselectAfterCopy)
{
var addedObject = new HitCircle { StartTime = 1000 };
@@ -123,11 +128,22 @@ namespace osu.Game.Tests.Visual.Editing
AddStep("move forward in time", () => EditorClock.Seek(2000));
+ if (deselectAfterCopy)
+ {
+ AddStep("deselect", () => EditorBeatmap.SelectedHitObjects.Clear());
+
+ AddUntilStep("timeline selection box is not visible", () => Editor.ChildrenOfType().First().ChildrenOfType().First().Alpha == 0);
+ AddUntilStep("composer selection box is not visible", () => Editor.ChildrenOfType().First().ChildrenOfType().First().Alpha == 0);
+ }
+
AddStep("paste hitobject", () => Editor.Paste());
AddAssert("are two objects", () => EditorBeatmap.HitObjects.Count == 2);
AddAssert("new object selected", () => EditorBeatmap.SelectedHitObjects.Single().StartTime == 2000);
+
+ AddUntilStep("timeline selection box is visible", () => Editor.ChildrenOfType().First().ChildrenOfType().First().Alpha > 0);
+ AddUntilStep("composer selection box is visible", () => Editor.ChildrenOfType().First().ChildrenOfType().First().Alpha > 0);
}
[Test]
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecorder.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecorder.cs
index 802dbf2021..b38f7a998d 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecorder.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecorder.cs
@@ -118,8 +118,8 @@ namespace osu.Game.Tests.Visual.Gameplay
public void TestBasic()
{
AddStep("move to center", () => InputManager.MoveMouseTo(recordingManager.ScreenSpaceDrawQuad.Centre));
- AddUntilStep("one frame recorded", () => replay.Frames.Count == 1);
- AddAssert("position matches", () => playbackManager.ChildrenOfType().First().Position == recordingManager.ChildrenOfType().First().Position);
+ AddUntilStep("at least one frame recorded", () => replay.Frames.Count > 0);
+ AddUntilStep("position matches", () => playbackManager.ChildrenOfType().First().Position == recordingManager.ChildrenOfType().First().Position);
}
[Test]
@@ -139,14 +139,16 @@ namespace osu.Game.Tests.Visual.Gameplay
public void TestLimitedFrameRate()
{
ScheduledDelegate moveFunction = null;
+ int initialFrameCount = 0;
AddStep("lower rate", () => recorder.RecordFrameRate = 2);
+ AddStep("count frames", () => initialFrameCount = replay.Frames.Count);
AddStep("move to center", () => InputManager.MoveMouseTo(recordingManager.ScreenSpaceDrawQuad.Centre));
AddStep("much move", () => moveFunction = Scheduler.AddDelayed(() =>
InputManager.MoveMouseTo(InputManager.CurrentState.Mouse.Position + new Vector2(-1, 0)), 10, true));
AddWaitStep("move", 10);
AddStep("stop move", () => moveFunction.Cancel());
- AddAssert("less than 10 frames recorded", () => replay.Frames.Count < 10);
+ AddAssert("less than 10 frames recorded", () => replay.Frames.Count - initialFrameCount < 10);
}
[Test]
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledColourPalette.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledColourPalette.cs
new file mode 100644
index 0000000000..826da17ca8
--- /dev/null
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledColourPalette.cs
@@ -0,0 +1,70 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using NUnit.Framework;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Utils;
+using osu.Game.Graphics.UserInterfaceV2;
+using osuTK.Graphics;
+
+namespace osu.Game.Tests.Visual.UserInterface
+{
+ public class TestSceneLabelledColourPalette : OsuTestScene
+ {
+ private LabelledColourPalette component;
+
+ [Test]
+ public void TestPalette([Values] bool hasDescription)
+ {
+ createColourPalette(hasDescription);
+
+ AddRepeatStep("add random colour", () => component.Colours.Add(randomColour()), 4);
+
+ AddStep("set custom prefix", () => component.ColourNamePrefix = "Combo");
+
+ AddRepeatStep("remove random colour", () =>
+ {
+ if (component.Colours.Count > 0)
+ component.Colours.RemoveAt(RNG.Next(component.Colours.Count));
+ }, 8);
+ }
+
+ private void createColourPalette(bool hasDescription = false)
+ {
+ AddStep("create component", () =>
+ {
+ Child = new Container
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Width = 500,
+ AutoSizeAxes = Axes.Y,
+ Child = component = new LabelledColourPalette
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ ColourNamePrefix = "My colour #"
+ }
+ };
+
+ component.Label = "a sample component";
+ component.Description = hasDescription ? "this text describes the component" : string.Empty;
+
+ component.Colours.AddRange(new[]
+ {
+ Color4.DarkRed,
+ Color4.Aquamarine,
+ Color4.Goldenrod,
+ Color4.Gainsboro
+ });
+ });
+ }
+
+ private Color4 randomColour() => new Color4(
+ RNG.NextSingle(),
+ RNG.NextSingle(),
+ RNG.NextSingle(),
+ 1);
+ }
+}
diff --git a/osu.Game/Beatmaps/Timing/TimeSignatures.cs b/osu.Game/Beatmaps/Timing/TimeSignatures.cs
index 147f6239b4..33e6342ae6 100644
--- a/osu.Game/Beatmaps/Timing/TimeSignatures.cs
+++ b/osu.Game/Beatmaps/Timing/TimeSignatures.cs
@@ -1,11 +1,16 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System.ComponentModel;
+
namespace osu.Game.Beatmaps.Timing
{
public enum TimeSignatures
{
+ [Description("4/4")]
SimpleQuadruple = 4,
+
+ [Description("3/4")]
SimpleTriple = 3
}
}
diff --git a/osu.Game/Configuration/SessionStatics.cs b/osu.Game/Configuration/SessionStatics.cs
index 71e1a1efcc..ac94c39bd2 100644
--- a/osu.Game/Configuration/SessionStatics.cs
+++ b/osu.Game/Configuration/SessionStatics.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using osu.Framework.Bindables;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays;
@@ -12,14 +13,18 @@ namespace osu.Game.Configuration
///
public class SessionStatics : InMemoryConfigManager
{
- protected override void InitialiseDefaults()
+ protected override void InitialiseDefaults() => ResetValues();
+
+ public void ResetValues()
{
- SetDefault(Static.LoginOverlayDisplayed, false);
- SetDefault(Static.MutedAudioNotificationShownOnce, false);
- SetDefault(Static.LowBatteryNotificationShownOnce, false);
- SetDefault(Static.LastHoverSoundPlaybackTime, (double?)null);
- SetDefault(Static.SeasonalBackgrounds, null);
+ ensureDefault(SetDefault(Static.LoginOverlayDisplayed, false));
+ ensureDefault(SetDefault(Static.MutedAudioNotificationShownOnce, false));
+ ensureDefault(SetDefault(Static.LowBatteryNotificationShownOnce, false));
+ ensureDefault(SetDefault(Static.LastHoverSoundPlaybackTime, (double?)null));
+ ensureDefault(SetDefault(Static.SeasonalBackgrounds, null));
}
+
+ private void ensureDefault(Bindable bindable) => bindable.SetDefault();
}
public enum Static
diff --git a/osu.Game/Graphics/OsuColour.cs b/osu.Game/Graphics/OsuColour.cs
index c3b9b6006c..15967c37c2 100644
--- a/osu.Game/Graphics/OsuColour.cs
+++ b/osu.Game/Graphics/OsuColour.cs
@@ -94,6 +94,18 @@ namespace osu.Game.Graphics
}
}
+ ///
+ /// Returns a foreground text colour that is supposed to contrast well with
+ /// the supplied .
+ ///
+ public static Color4 ForegroundTextColourFor(Color4 backgroundColour)
+ {
+ // formula taken from the RGB->YIQ conversions: https://en.wikipedia.org/wiki/YIQ
+ // brightness here is equivalent to the Y component in the above colour model, which is a rough estimate of lightness.
+ float brightness = 0.299f * backgroundColour.R + 0.587f * backgroundColour.G + 0.114f * backgroundColour.B;
+ return Gray(brightness > 0.5f ? 0.2f : 0.9f);
+ }
+
// See https://github.com/ppy/osu-web/blob/master/resources/assets/less/colors.less
public readonly Color4 PurpleLighter = Color4Extensions.FromHex(@"eeeeff");
public readonly Color4 PurpleLight = Color4Extensions.FromHex(@"aa88ff");
diff --git a/osu.Game/Graphics/UserInterface/DownloadButton.cs b/osu.Game/Graphics/UserInterface/DownloadButton.cs
index 7a8db158c1..af270f30ae 100644
--- a/osu.Game/Graphics/UserInterface/DownloadButton.cs
+++ b/osu.Game/Graphics/UserInterface/DownloadButton.cs
@@ -27,7 +27,7 @@ namespace osu.Game.Graphics.UserInterface
[BackgroundDependencyLoader]
private void load()
{
- AddInternal(checkmark = new SpriteIcon
+ Add(checkmark = new SpriteIcon
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
diff --git a/osu.Game/Graphics/UserInterfaceV2/ColourDisplay.cs b/osu.Game/Graphics/UserInterfaceV2/ColourDisplay.cs
new file mode 100644
index 0000000000..01d91f7cfd
--- /dev/null
+++ b/osu.Game/Graphics/UserInterfaceV2/ColourDisplay.cs
@@ -0,0 +1,107 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Extensions.Color4Extensions;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Framework.Graphics.UserInterface;
+using osu.Framework.Localisation;
+using osu.Game.Graphics.Sprites;
+using osuTK;
+using osuTK.Graphics;
+
+namespace osu.Game.Graphics.UserInterfaceV2
+{
+ ///
+ /// A component which displays a colour along with related description text.
+ ///
+ public class ColourDisplay : CompositeDrawable, IHasCurrentValue
+ {
+ private readonly BindableWithCurrent current = new BindableWithCurrent();
+
+ private Box fill;
+ private OsuSpriteText colourHexCode;
+ private OsuSpriteText colourName;
+
+ public Bindable Current
+ {
+ get => current.Current;
+ set => current.Current = value;
+ }
+
+ private LocalisableString name;
+
+ public LocalisableString ColourName
+ {
+ get => name;
+ set
+ {
+ if (name == value)
+ return;
+
+ name = value;
+
+ colourName.Text = name;
+ }
+ }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ AutoSizeAxes = Axes.Y;
+ Width = 100;
+
+ InternalChild = new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Vertical,
+ Spacing = new Vector2(0, 10),
+ Children = new Drawable[]
+ {
+ new CircularContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ Height = 100,
+ Masking = true,
+ Children = new Drawable[]
+ {
+ fill = new Box
+ {
+ RelativeSizeAxes = Axes.Both
+ },
+ colourHexCode = new OsuSpriteText
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Font = OsuFont.Default.With(size: 12)
+ }
+ }
+ },
+ colourName = new OsuSpriteText
+ {
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre
+ }
+ }
+ };
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ current.BindValueChanged(_ => updateColour(), true);
+ }
+
+ private void updateColour()
+ {
+ fill.Colour = current.Value;
+ colourHexCode.Text = current.Value.ToHex();
+ colourHexCode.Colour = OsuColour.ForegroundTextColourFor(current.Value);
+ }
+ }
+}
diff --git a/osu.Game/Graphics/UserInterfaceV2/ColourPalette.cs b/osu.Game/Graphics/UserInterfaceV2/ColourPalette.cs
new file mode 100644
index 0000000000..ba950048dc
--- /dev/null
+++ b/osu.Game/Graphics/UserInterfaceV2/ColourPalette.cs
@@ -0,0 +1,119 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Linq;
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Graphics.Sprites;
+using osuTK;
+using osuTK.Graphics;
+
+namespace osu.Game.Graphics.UserInterfaceV2
+{
+ ///
+ /// A component which displays a collection of colours in individual s.
+ ///
+ public class ColourPalette : CompositeDrawable
+ {
+ public BindableList Colours { get; } = new BindableList();
+
+ private string colourNamePrefix = "Colour";
+
+ public string ColourNamePrefix
+ {
+ get => colourNamePrefix;
+ set
+ {
+ if (colourNamePrefix == value)
+ return;
+
+ colourNamePrefix = value;
+
+ if (IsLoaded)
+ reindexItems();
+ }
+ }
+
+ private FillFlowContainer palette;
+ private Container placeholder;
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ RelativeSizeAxes = Axes.X;
+ AutoSizeAxes = Axes.Y;
+
+ InternalChildren = new Drawable[]
+ {
+ palette = new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Spacing = new Vector2(10),
+ Direction = FillDirection.Full
+ },
+ placeholder = new Container
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Child = new OsuSpriteText
+ {
+ Anchor = Anchor.CentreRight,
+ Origin = Anchor.CentreRight,
+ Text = "(none)",
+ Font = OsuFont.Default.With(weight: FontWeight.Bold)
+ }
+ }
+ };
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ Colours.BindCollectionChanged((_, __) => updatePalette(), true);
+ FinishTransforms(true);
+ }
+
+ private const int fade_duration = 200;
+
+ private void updatePalette()
+ {
+ palette.Clear();
+
+ if (Colours.Any())
+ {
+ palette.FadeIn(fade_duration, Easing.OutQuint);
+ placeholder.FadeOut(fade_duration, Easing.OutQuint);
+ }
+ else
+ {
+ palette.FadeOut(fade_duration, Easing.OutQuint);
+ placeholder.FadeIn(fade_duration, Easing.OutQuint);
+ }
+
+ foreach (var item in Colours)
+ {
+ palette.Add(new ColourDisplay
+ {
+ Current = { Value = item }
+ });
+ }
+
+ reindexItems();
+ }
+
+ private void reindexItems()
+ {
+ int index = 1;
+
+ foreach (var colour in palette)
+ {
+ colour.ColourName = $"{colourNamePrefix} {index}";
+ index += 1;
+ }
+ }
+ }
+}
diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledColourPalette.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledColourPalette.cs
new file mode 100644
index 0000000000..58443953bc
--- /dev/null
+++ b/osu.Game/Graphics/UserInterfaceV2/LabelledColourPalette.cs
@@ -0,0 +1,26 @@
+// 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 osuTK.Graphics;
+
+namespace osu.Game.Graphics.UserInterfaceV2
+{
+ public class LabelledColourPalette : LabelledDrawable
+ {
+ public LabelledColourPalette()
+ : base(true)
+ {
+ }
+
+ public BindableList Colours => Component.Colours;
+
+ public string ColourNamePrefix
+ {
+ get => Component.ColourNamePrefix;
+ set => Component.ColourNamePrefix = value;
+ }
+
+ protected override ColourPalette CreateComponent() => new ColourPalette();
+ }
+}
diff --git a/osu.Game/Input/IdleTracker.cs b/osu.Game/Input/IdleTracker.cs
index 63a6348b57..2d6a21d1cf 100644
--- a/osu.Game/Input/IdleTracker.cs
+++ b/osu.Game/Input/IdleTracker.cs
@@ -42,6 +42,12 @@ namespace osu.Game.Input
RelativeSizeAxes = Axes.Both;
}
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+ updateLastInteractionTime();
+ }
+
protected override void Update()
{
base.Update();
diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs
index 809e5d3c1b..28f32ba455 100644
--- a/osu.Game/OsuGame.cs
+++ b/osu.Game/OsuGame.cs
@@ -577,6 +577,15 @@ namespace osu.Game
dependencies.CacheAs(idleTracker = new GameIdleTracker(6000));
+ var sessionIdleTracker = new GameIdleTracker(300000);
+ sessionIdleTracker.IsIdle.BindValueChanged(idle =>
+ {
+ if (idle.NewValue)
+ SessionStatics.ResetValues();
+ });
+
+ Add(sessionIdleTracker);
+
AddRange(new Drawable[]
{
new VolumeControlReceptor
diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs
index 406819cbd2..fbe4022cc1 100644
--- a/osu.Game/OsuGameBase.cs
+++ b/osu.Game/OsuGameBase.cs
@@ -61,6 +61,8 @@ namespace osu.Game
protected OsuConfigManager LocalConfig;
+ protected SessionStatics SessionStatics { get; private set; }
+
protected BeatmapManager BeatmapManager;
protected ScoreManager ScoreManager;
@@ -289,7 +291,7 @@ namespace osu.Game
if (powerStatus != null)
dependencies.CacheAs(powerStatus);
- dependencies.Cache(new SessionStatics());
+ dependencies.Cache(SessionStatics = new SessionStatics());
dependencies.Cache(new OsuColour());
RegisterImportHandler(BeatmapManager);
diff --git a/osu.Game/Overlays/Volume/VolumeControlReceptor.cs b/osu.Game/Overlays/Volume/VolumeControlReceptor.cs
index 34b86b2f81..ae9c2eb394 100644
--- a/osu.Game/Overlays/Volume/VolumeControlReceptor.cs
+++ b/osu.Game/Overlays/Volume/VolumeControlReceptor.cs
@@ -44,6 +44,9 @@ namespace osu.Game.Overlays.Volume
protected override bool OnScroll(ScrollEvent e)
{
+ if (e.ScrollDelta.Y == 0)
+ return false;
+
// forward any unhandled mouse scroll events to the volume control.
ScrollActionRequested?.Invoke(GlobalAction.IncreaseVolume, e.ScrollDelta.Y, e.IsPrecise);
return true;
diff --git a/osu.Game/Overlays/Volume/VolumeMeter.cs b/osu.Game/Overlays/Volume/VolumeMeter.cs
index 202eac93ea..f1f21bec49 100644
--- a/osu.Game/Overlays/Volume/VolumeMeter.cs
+++ b/osu.Game/Overlays/Volume/VolumeMeter.cs
@@ -245,6 +245,9 @@ namespace osu.Game.Overlays.Volume
private void adjust(double delta, bool isPrecise)
{
+ if (delta == 0)
+ return;
+
// every adjust increment increases the rate at which adjustments happen up to a cutoff.
// this debounce will reset on inactivity.
accelerationDebounce?.Cancel();
diff --git a/osu.Game/Rulesets/UI/ReplayRecorder.cs b/osu.Game/Rulesets/UI/ReplayRecorder.cs
index a4d46e3888..643ded4cad 100644
--- a/osu.Game/Rulesets/UI/ReplayRecorder.cs
+++ b/osu.Game/Rulesets/UI/ReplayRecorder.cs
@@ -58,6 +58,12 @@ namespace osu.Game.Rulesets.UI
spectatorStreaming?.EndPlaying();
}
+ protected override void Update()
+ {
+ base.Update();
+ recordFrame(false);
+ }
+
protected override bool OnMouseMove(MouseMoveEvent e)
{
recordFrame(false);
diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs
index 389ef78ed5..b06e982859 100644
--- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs
@@ -33,10 +33,14 @@ namespace osu.Game.Screens.Edit.Compose.Components
///
public class SelectionHandler : CompositeDrawable, IKeyBindingHandler, IHasContextMenu
{
+ ///
+ /// The currently selected blueprints.
+ /// Should be used when operations are dealing directly with the visible blueprints.
+ /// For more general selection operations, use instead.
+ ///
public IEnumerable SelectedBlueprints => selectedBlueprints;
- private readonly List selectedBlueprints;
- public int SelectedCount => selectedBlueprints.Count;
+ private readonly List selectedBlueprints;
private Drawable content;
@@ -295,7 +299,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
///
private void updateVisibility()
{
- int count = selectedBlueprints.Count;
+ int count = EditorBeatmap.SelectedHitObjects.Count;
selectionDetailsText.Text = count > 0 ? count.ToString() : string.Empty;
diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs
index 105e04d441..0425370ae5 100644
--- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs
@@ -158,10 +158,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
circle.Colour = comboColour;
var col = circle.Colour.TopLeft.Linear;
- float brightness = col.R + col.G + col.B;
-
- // decide the combo index colour based on brightness?
- colouredComponents.Colour = OsuColour.Gray(brightness > 0.5f ? 0.2f : 0.9f);
+ colouredComponents.Colour = OsuColour.ForegroundTextColourFor(col);
}
protected override void Update()
diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs
index 4f1b0484d2..4bf4a3b8f3 100644
--- a/osu.Game/Screens/Edit/EditorBeatmap.cs
+++ b/osu.Game/Screens/Edit/EditorBeatmap.cs
@@ -46,6 +46,7 @@ namespace osu.Game.Screens.Edit
public readonly IBeatmap PlayableBeatmap;
+ [CanBeNull]
public readonly ISkin BeatmapSkin;
[Resolved]
diff --git a/osu.Game/Screens/Edit/EditorTable.cs b/osu.Game/Screens/Edit/EditorTable.cs
index ef1c88db9a..815f3ed0ea 100644
--- a/osu.Game/Screens/Edit/EditorTable.cs
+++ b/osu.Game/Screens/Edit/EditorTable.cs
@@ -9,6 +9,7 @@ using osu.Framework.Input.Events;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
+using osu.Game.Overlays;
using osuTK.Graphics;
namespace osu.Game.Screens.Edit
@@ -19,7 +20,7 @@ namespace osu.Game.Screens.Edit
protected const float ROW_HEIGHT = 25;
- protected const int TEXT_SIZE = 14;
+ public const int TEXT_SIZE = 14;
protected readonly FillFlowContainer BackgroundFlow;
@@ -93,10 +94,10 @@ namespace osu.Game.Screens.Edit
private Color4 colourSelected;
[BackgroundDependencyLoader]
- private void load(OsuColour colours)
+ private void load(OverlayColourProvider colours)
{
- hoveredBackground.Colour = colourHover = colours.BlueDarker;
- colourSelected = colours.YellowDarker;
+ hoveredBackground.Colour = colourHover = colours.Background1;
+ colourSelected = colours.Colour3;
}
private bool selected;
diff --git a/osu.Game/Screens/Edit/RoundedContentEditorScreen.cs b/osu.Game/Screens/Edit/RoundedContentEditorScreen.cs
new file mode 100644
index 0000000000..a55ae3f635
--- /dev/null
+++ b/osu.Game/Screens/Edit/RoundedContentEditorScreen.cs
@@ -0,0 +1,61 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Graphics;
+using osu.Game.Overlays;
+
+namespace osu.Game.Screens.Edit
+{
+ public class RoundedContentEditorScreen : EditorScreen
+ {
+ public const int HORIZONTAL_PADDING = 100;
+
+ [Resolved]
+ private OsuColour colours { get; set; }
+
+ [Cached]
+ protected readonly OverlayColourProvider ColourProvider;
+
+ private Container roundedContent;
+
+ protected override Container Content => roundedContent;
+
+ public RoundedContentEditorScreen(EditorScreenMode mode)
+ : base(mode)
+ {
+ ColourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
+ }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ base.Content.Add(new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ Padding = new MarginPadding(50),
+ Child = new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ Masking = true,
+ CornerRadius = 10,
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ Colour = ColourProvider.Dark4,
+ RelativeSizeAxes = Axes.Both,
+ },
+ roundedContent = new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ },
+ }
+ }
+ });
+ }
+ }
+}
diff --git a/osu.Game/Screens/Edit/Setup/ColoursSection.cs b/osu.Game/Screens/Edit/Setup/ColoursSection.cs
new file mode 100644
index 0000000000..cb7deadcb7
--- /dev/null
+++ b/osu.Game/Screens/Edit/Setup/ColoursSection.cs
@@ -0,0 +1,37 @@
+// 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.Graphics;
+using osu.Framework.Localisation;
+using osu.Game.Graphics.UserInterfaceV2;
+using osu.Game.Skinning;
+using osuTK.Graphics;
+
+namespace osu.Game.Screens.Edit.Setup
+{
+ internal class ColoursSection : SetupSection
+ {
+ public override LocalisableString Title => "Colours";
+
+ private LabelledColourPalette comboColours;
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ Children = new Drawable[]
+ {
+ comboColours = new LabelledColourPalette
+ {
+ Label = "Hitcircle / Slider Combos",
+ ColourNamePrefix = "Combo"
+ }
+ };
+
+ var colours = Beatmap.BeatmapSkin?.GetConfig>(GlobalSkinColours.ComboColours)?.Value;
+ if (colours != null)
+ comboColours.Colours.AddRange(colours);
+ }
+ }
+}
diff --git a/osu.Game/Screens/Edit/Setup/SetupScreen.cs b/osu.Game/Screens/Edit/Setup/SetupScreen.cs
index 70671b487c..0af7cf095b 100644
--- a/osu.Game/Screens/Edit/Setup/SetupScreen.cs
+++ b/osu.Game/Screens/Edit/Setup/SetupScreen.cs
@@ -3,24 +3,12 @@
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.Overlays;
namespace osu.Game.Screens.Edit.Setup
{
- public class SetupScreen : EditorScreen
+ public class SetupScreen : RoundedContentEditorScreen
{
- public const int HORIZONTAL_PADDING = 100;
-
- [Resolved]
- private OsuColour colours { get; set; }
-
- [Cached]
- protected readonly OverlayColourProvider ColourProvider;
-
[Cached]
private SectionsContainer sections = new SectionsContainer();
@@ -30,42 +18,26 @@ namespace osu.Game.Screens.Edit.Setup
public SetupScreen()
: base(EditorScreenMode.SongSetup)
{
- ColourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
}
[BackgroundDependencyLoader]
private void load()
{
- Child = new Container
+ AddRange(new Drawable[]
{
- RelativeSizeAxes = Axes.Both,
- Padding = new MarginPadding(50),
- Child = new Container
+ sections = new SectionsContainer
{
+ FixedHeader = header,
RelativeSizeAxes = Axes.Both,
- Masking = true,
- CornerRadius = 10,
- Children = new Drawable[]
+ Children = new SetupSection[]
{
- new Box
- {
- Colour = ColourProvider.Dark4,
- RelativeSizeAxes = Axes.Both,
- },
- sections = new SectionsContainer
- {
- FixedHeader = header,
- RelativeSizeAxes = Axes.Both,
- Children = new SetupSection[]
- {
- new ResourcesSection(),
- new MetadataSection(),
- new DifficultySection(),
- }
- },
+ new ResourcesSection(),
+ new MetadataSection(),
+ new DifficultySection(),
+ new ColoursSection()
}
- }
- };
+ },
+ });
}
}
}
diff --git a/osu.Game/Screens/Edit/Setup/SetupScreenHeader.cs b/osu.Game/Screens/Edit/Setup/SetupScreenHeader.cs
index 06aad69afa..10daacc359 100644
--- a/osu.Game/Screens/Edit/Setup/SetupScreenHeader.cs
+++ b/osu.Game/Screens/Edit/Setup/SetupScreenHeader.cs
@@ -93,7 +93,7 @@ namespace osu.Game.Screens.Edit.Setup
public SetupScreenTabControl()
{
- TabContainer.Margin = new MarginPadding { Horizontal = SetupScreen.HORIZONTAL_PADDING };
+ TabContainer.Margin = new MarginPadding { Horizontal = RoundedContentEditorScreen.HORIZONTAL_PADDING };
AddInternal(background = new Box
{
diff --git a/osu.Game/Screens/Edit/Setup/SetupSection.cs b/osu.Game/Screens/Edit/Setup/SetupSection.cs
index de62c3a468..b3ae15900f 100644
--- a/osu.Game/Screens/Edit/Setup/SetupSection.cs
+++ b/osu.Game/Screens/Edit/Setup/SetupSection.cs
@@ -33,7 +33,7 @@ namespace osu.Game.Screens.Edit.Setup
Padding = new MarginPadding
{
Vertical = 10,
- Horizontal = SetupScreen.HORIZONTAL_PADDING
+ Horizontal = RoundedContentEditorScreen.HORIZONTAL_PADDING
};
InternalChild = new FillFlowContainer
diff --git a/osu.Game/Screens/Edit/Timing/ControlPointSettings.cs b/osu.Game/Screens/Edit/Timing/ControlPointSettings.cs
index c40061b97c..921fa675b3 100644
--- a/osu.Game/Screens/Edit/Timing/ControlPointSettings.cs
+++ b/osu.Game/Screens/Edit/Timing/ControlPointSettings.cs
@@ -6,15 +6,15 @@ 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.Overlays;
namespace osu.Game.Screens.Edit.Timing
{
public class ControlPointSettings : CompositeDrawable
{
[BackgroundDependencyLoader]
- private void load(OsuColour colours)
+ private void load(OverlayColourProvider colours)
{
RelativeSizeAxes = Axes.Both;
@@ -22,7 +22,7 @@ namespace osu.Game.Screens.Edit.Timing
{
new Box
{
- Colour = colours.Gray3,
+ Colour = colours.Background4,
RelativeSizeAxes = Axes.Both,
},
new OsuScrollContainer
diff --git a/osu.Game/Screens/Edit/Timing/ControlPointTable.cs b/osu.Game/Screens/Edit/Timing/ControlPointTable.cs
index dd51056bf1..fe63138d28 100644
--- a/osu.Game/Screens/Edit/Timing/ControlPointTable.cs
+++ b/osu.Game/Screens/Edit/Timing/ControlPointTable.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.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
@@ -12,8 +13,8 @@ using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Extensions;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
+using osu.Game.Screens.Edit.Timing.RowAttributes;
using osuTK;
-using osuTK.Graphics;
namespace osu.Game.Screens.Edit.Timing
{
@@ -25,6 +26,8 @@ namespace osu.Game.Screens.Edit.Timing
[Resolved]
private EditorClock clock { get; set; }
+ public const float TIMING_COLUMN_WIDTH = 220;
+
public IEnumerable ControlGroups
{
set
@@ -66,44 +69,62 @@ namespace osu.Game.Screens.Edit.Timing
{
var columns = new List
{
- new TableColumn(string.Empty, Anchor.Centre, new Dimension(GridSizeMode.AutoSize)),
- new TableColumn("Time", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)),
- new TableColumn(),
+ new TableColumn("Time", Anchor.CentreLeft, new Dimension(GridSizeMode.Absolute, TIMING_COLUMN_WIDTH)),
new TableColumn("Attributes", Anchor.CentreLeft),
};
return columns.ToArray();
}
- private Drawable[] createContent(int index, ControlPointGroup group) => new Drawable[]
+ private Drawable[] createContent(int index, ControlPointGroup group)
{
- new OsuSpriteText
+ return new Drawable[]
{
- Text = $"#{index + 1}",
- Font = OsuFont.GetFont(size: TEXT_SIZE, weight: FontWeight.Bold),
- Margin = new MarginPadding(10)
- },
- new OsuSpriteText
- {
- Text = group.Time.ToEditorFormattedString(),
- Font = OsuFont.GetFont(size: TEXT_SIZE, weight: FontWeight.Bold)
- },
- null,
- new ControlGroupAttributes(group),
- };
+ new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.Y,
+ Width = TIMING_COLUMN_WIDTH,
+ Spacing = new Vector2(5),
+ Children = new Drawable[]
+ {
+ new OsuSpriteText
+ {
+ Text = group.Time.ToEditorFormattedString(),
+ Font = OsuFont.GetFont(size: TEXT_SIZE, weight: FontWeight.Bold),
+ Width = 60,
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreLeft,
+ },
+ new ControlGroupAttributes(group, c => c is TimingControlPoint)
+ {
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreLeft,
+ }
+ }
+ },
+ new ControlGroupAttributes(group, c => !(c is TimingControlPoint))
+ };
+ }
private class ControlGroupAttributes : CompositeDrawable
{
+ private readonly Func matchFunction;
+
private readonly IBindableList controlPoints = new BindableList();
private readonly FillFlowContainer fill;
- public ControlGroupAttributes(ControlPointGroup group)
+ public ControlGroupAttributes(ControlPointGroup group, Func matchFunction)
{
- RelativeSizeAxes = Axes.Both;
+ this.matchFunction = matchFunction;
+
+ AutoSizeAxes = Axes.X;
+ RelativeSizeAxes = Axes.Y;
+
InternalChild = fill = new FillFlowContainer
{
- RelativeSizeAxes = Axes.Both,
+ AutoSizeAxes = Axes.X,
+ RelativeSizeAxes = Axes.Y,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(2)
};
@@ -128,30 +149,30 @@ namespace osu.Game.Screens.Edit.Timing
private void createChildren()
{
- fill.ChildrenEnumerable = controlPoints.Select(createAttribute).Where(c => c != null);
+ fill.ChildrenEnumerable = controlPoints
+ .Where(matchFunction)
+ .Select(createAttribute)
+ .Where(c => c != null)
+ // arbitrary ordering to make timing points first.
+ // probably want to explicitly define order in the future.
+ .OrderByDescending(c => c.GetType().Name);
}
private Drawable createAttribute(ControlPoint controlPoint)
{
- Color4 colour = controlPoint.GetRepresentingColour(colours);
-
switch (controlPoint)
{
case TimingControlPoint timing:
- return new RowAttribute("timing", () => $"{60000 / timing.BeatLength:n1}bpm {timing.TimeSignature}", colour);
+ return new TimingRowAttribute(timing);
case DifficultyControlPoint difficulty:
-
- return new RowAttribute("difficulty", () => $"{difficulty.SpeedMultiplier:n2}x", colour);
+ return new DifficultyRowAttribute(difficulty);
case EffectControlPoint effect:
- return new RowAttribute("effect", () => string.Join(" ",
- effect.KiaiMode ? "Kiai" : string.Empty,
- effect.OmitFirstBarLine ? "NoBarLine" : string.Empty
- ).Trim(), colour);
+ return new EffectRowAttribute(effect);
case SampleControlPoint sample:
- return new RowAttribute("sample", () => $"{sample.SampleBank} {sample.SampleVolume}%", colour);
+ return new SampleRowAttribute(sample);
}
return null;
diff --git a/osu.Game/Screens/Edit/Timing/RowAttribute.cs b/osu.Game/Screens/Edit/Timing/RowAttribute.cs
index 2757e08026..74d43628e1 100644
--- a/osu.Game/Screens/Edit/Timing/RowAttribute.cs
+++ b/osu.Game/Screens/Edit/Timing/RowAttribute.cs
@@ -1,33 +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 osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
+using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
-using osuTK.Graphics;
+using osu.Game.Overlays;
+using osuTK;
namespace osu.Game.Screens.Edit.Timing
{
- public class RowAttribute : CompositeDrawable, IHasTooltip
+ public class RowAttribute : CompositeDrawable
{
- private readonly string header;
- private readonly Func content;
- private readonly Color4 colour;
+ protected readonly ControlPoint Point;
- public RowAttribute(string header, Func content, Color4 colour)
+ private readonly string label;
+
+ protected FillFlowContainer Content { get; private set; }
+
+ public RowAttribute(ControlPoint point, string label)
{
- this.header = header;
- this.content = content;
- this.colour = colour;
+ Point = point;
+
+ this.label = label;
}
[BackgroundDependencyLoader]
- private void load(OsuColour colours)
+ private void load(OsuColour colours, OverlayColourProvider overlayColours)
{
AutoSizeAxes = Axes.X;
@@ -37,27 +39,43 @@ namespace osu.Game.Screens.Edit.Timing
Origin = Anchor.CentreLeft;
Masking = true;
- CornerRadius = 5;
+ CornerRadius = 3;
InternalChildren = new Drawable[]
{
new Box
{
- Colour = colour,
+ Colour = overlayColours.Background4,
RelativeSizeAxes = Axes.Both,
},
- new OsuSpriteText
+ Content = new FillFlowContainer
{
- Padding = new MarginPadding(2),
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- Font = OsuFont.Default.With(weight: FontWeight.SemiBold, size: 12),
- Text = header,
- Colour = colours.Gray0
- },
+ RelativeSizeAxes = Axes.Y,
+ AutoSizeAxes = Axes.X,
+ Direction = FillDirection.Horizontal,
+ Margin = new MarginPadding { Horizontal = 5 },
+ Spacing = new Vector2(5),
+ Children = new Drawable[]
+ {
+ new Circle
+ {
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreLeft,
+ Colour = Point.GetRepresentingColour(colours),
+ RelativeSizeAxes = Axes.Y,
+ Size = new Vector2(4, 0.6f),
+ },
+ new OsuSpriteText
+ {
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreLeft,
+ Padding = new MarginPadding(3),
+ Font = OsuFont.Default.With(weight: FontWeight.Bold, size: 12),
+ Text = label,
+ },
+ },
+ }
};
}
-
- public string TooltipText => content();
}
}
diff --git a/osu.Game/Screens/Edit/Timing/RowAttributes/AttributeProgressBar.cs b/osu.Game/Screens/Edit/Timing/RowAttributes/AttributeProgressBar.cs
new file mode 100644
index 0000000000..6f7e790489
--- /dev/null
+++ b/osu.Game/Screens/Edit/Timing/RowAttributes/AttributeProgressBar.cs
@@ -0,0 +1,41 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Game.Beatmaps.ControlPoints;
+using osu.Game.Graphics;
+using osu.Game.Graphics.UserInterface;
+using osu.Game.Overlays;
+using osuTK;
+
+namespace osu.Game.Screens.Edit.Timing.RowAttributes
+{
+ public class AttributeProgressBar : ProgressBar
+ {
+ private readonly ControlPoint controlPoint;
+
+ public AttributeProgressBar(ControlPoint controlPoint)
+ : base(false)
+ {
+ this.controlPoint = controlPoint;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours, OverlayColourProvider overlayColours)
+ {
+ Anchor = Anchor.CentreLeft;
+ Origin = Anchor.CentreLeft;
+
+ Masking = true;
+
+ RelativeSizeAxes = Axes.None;
+
+ Size = new Vector2(80, 8);
+ CornerRadius = Height / 2;
+
+ BackgroundColour = overlayColours.Background6;
+ FillColour = controlPoint.GetRepresentingColour(colours);
+ }
+ }
+}
diff --git a/osu.Game/Screens/Edit/Timing/RowAttributes/AttributeText.cs b/osu.Game/Screens/Edit/Timing/RowAttributes/AttributeText.cs
new file mode 100644
index 0000000000..d0a51f9faa
--- /dev/null
+++ b/osu.Game/Screens/Edit/Timing/RowAttributes/AttributeText.cs
@@ -0,0 +1,32 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Game.Beatmaps.ControlPoints;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Sprites;
+
+namespace osu.Game.Screens.Edit.Timing.RowAttributes
+{
+ public class AttributeText : OsuSpriteText
+ {
+ private readonly ControlPoint controlPoint;
+
+ public AttributeText(ControlPoint controlPoint)
+ {
+ this.controlPoint = controlPoint;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ Anchor = Anchor.CentreLeft;
+ Origin = Anchor.CentreLeft;
+
+ Padding = new MarginPadding(6);
+ Font = OsuFont.Default.With(weight: FontWeight.Bold, size: 12);
+ Colour = controlPoint.GetRepresentingColour(colours);
+ }
+ }
+}
diff --git a/osu.Game/Screens/Edit/Timing/RowAttributes/DifficultyRowAttribute.cs b/osu.Game/Screens/Edit/Timing/RowAttributes/DifficultyRowAttribute.cs
new file mode 100644
index 0000000000..7b553ac7ad
--- /dev/null
+++ b/osu.Game/Screens/Edit/Timing/RowAttributes/DifficultyRowAttribute.cs
@@ -0,0 +1,44 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Game.Beatmaps.ControlPoints;
+using osu.Game.Graphics.Sprites;
+
+namespace osu.Game.Screens.Edit.Timing.RowAttributes
+{
+ public class DifficultyRowAttribute : RowAttribute
+ {
+ private readonly BindableNumber speedMultiplier;
+
+ private OsuSpriteText text;
+
+ public DifficultyRowAttribute(DifficultyControlPoint difficulty)
+ : base(difficulty, "difficulty")
+ {
+ speedMultiplier = difficulty.SpeedMultiplierBindable.GetBoundCopy();
+ }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ Content.AddRange(new Drawable[]
+ {
+ new AttributeProgressBar(Point)
+ {
+ Current = speedMultiplier,
+ },
+ text = new AttributeText(Point)
+ {
+ Width = 40,
+ },
+ });
+
+ speedMultiplier.BindValueChanged(_ => updateText(), true);
+ }
+
+ private void updateText() => text.Text = $"{speedMultiplier.Value:n2}x";
+ }
+}
diff --git a/osu.Game/Screens/Edit/Timing/RowAttributes/EffectRowAttribute.cs b/osu.Game/Screens/Edit/Timing/RowAttributes/EffectRowAttribute.cs
new file mode 100644
index 0000000000..812407d6da
--- /dev/null
+++ b/osu.Game/Screens/Edit/Timing/RowAttributes/EffectRowAttribute.cs
@@ -0,0 +1,38 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Game.Beatmaps.ControlPoints;
+
+namespace osu.Game.Screens.Edit.Timing.RowAttributes
+{
+ public class EffectRowAttribute : RowAttribute
+ {
+ private readonly Bindable kiaiMode;
+ private readonly Bindable omitBarLine;
+ private AttributeText kiaiModeBubble;
+ private AttributeText omitBarLineBubble;
+
+ public EffectRowAttribute(EffectControlPoint effect)
+ : base(effect, "effect")
+ {
+ kiaiMode = effect.KiaiModeBindable.GetBoundCopy();
+ omitBarLine = effect.OmitFirstBarLineBindable.GetBoundCopy();
+ }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ Content.AddRange(new Drawable[]
+ {
+ kiaiModeBubble = new AttributeText(Point) { Text = "kiai" },
+ omitBarLineBubble = new AttributeText(Point) { Text = "no barline" },
+ });
+
+ kiaiMode.BindValueChanged(enabled => kiaiModeBubble.FadeTo(enabled.NewValue ? 1 : 0), true);
+ omitBarLine.BindValueChanged(enabled => omitBarLineBubble.FadeTo(enabled.NewValue ? 1 : 0), true);
+ }
+ }
+}
diff --git a/osu.Game/Screens/Edit/Timing/RowAttributes/SampleRowAttribute.cs b/osu.Game/Screens/Edit/Timing/RowAttributes/SampleRowAttribute.cs
new file mode 100644
index 0000000000..ac0797dba1
--- /dev/null
+++ b/osu.Game/Screens/Edit/Timing/RowAttributes/SampleRowAttribute.cs
@@ -0,0 +1,57 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Game.Beatmaps.ControlPoints;
+using osu.Game.Graphics.Sprites;
+
+namespace osu.Game.Screens.Edit.Timing.RowAttributes
+{
+ public class SampleRowAttribute : RowAttribute
+ {
+ private AttributeText sampleText;
+ private OsuSpriteText volumeText;
+
+ private readonly Bindable sampleBank;
+ private readonly BindableNumber volume;
+
+ public SampleRowAttribute(SampleControlPoint sample)
+ : base(sample, "sample")
+ {
+ sampleBank = sample.SampleBankBindable.GetBoundCopy();
+ volume = sample.SampleVolumeBindable.GetBoundCopy();
+ }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ AttributeProgressBar progress;
+
+ Content.AddRange(new Drawable[]
+ {
+ sampleText = new AttributeText(Point),
+ progress = new AttributeProgressBar(Point),
+ volumeText = new AttributeText(Point)
+ {
+ Width = 40,
+ },
+ });
+
+ volume.BindValueChanged(vol =>
+ {
+ progress.Current.Value = vol.NewValue / 100f;
+ updateText();
+ }, true);
+
+ sampleBank.BindValueChanged(_ => updateText(), true);
+ }
+
+ private void updateText()
+ {
+ volumeText.Text = $"{volume.Value}%";
+ sampleText.Text = $"{sampleBank.Value}";
+ }
+ }
+}
diff --git a/osu.Game/Screens/Edit/Timing/RowAttributes/TimingRowAttribute.cs b/osu.Game/Screens/Edit/Timing/RowAttributes/TimingRowAttribute.cs
new file mode 100644
index 0000000000..ab840e56a7
--- /dev/null
+++ b/osu.Game/Screens/Edit/Timing/RowAttributes/TimingRowAttribute.cs
@@ -0,0 +1,38 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Extensions;
+using osu.Game.Beatmaps.ControlPoints;
+using osu.Game.Beatmaps.Timing;
+using osu.Game.Graphics.Sprites;
+
+namespace osu.Game.Screens.Edit.Timing.RowAttributes
+{
+ public class TimingRowAttribute : RowAttribute
+ {
+ private readonly BindableNumber beatLength;
+ private readonly Bindable timeSignature;
+ private OsuSpriteText text;
+
+ public TimingRowAttribute(TimingControlPoint timing)
+ : base(timing, "timing")
+ {
+ timeSignature = timing.TimeSignatureBindable.GetBoundCopy();
+ beatLength = timing.BeatLengthBindable.GetBoundCopy();
+ }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ Content.Add(text = new AttributeText(Point));
+
+ timeSignature.BindValueChanged(_ => updateText());
+ beatLength.BindValueChanged(_ => updateText(), true);
+ }
+
+ private void updateText() =>
+ text.Text = $"{60000 / beatLength.Value:n1}bpm {timeSignature.Value.GetDescription()}";
+ }
+}
diff --git a/osu.Game/Screens/Edit/Timing/Section.cs b/osu.Game/Screens/Edit/Timing/Section.cs
index 5269fa9774..8659b7aff6 100644
--- a/osu.Game/Screens/Edit/Timing/Section.cs
+++ b/osu.Game/Screens/Edit/Timing/Section.cs
@@ -8,8 +8,9 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps.ControlPoints;
-using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
+using osu.Game.Overlays;
+using osuTK;
namespace osu.Game.Screens.Edit.Timing
{
@@ -23,7 +24,7 @@ namespace osu.Game.Screens.Edit.Timing
protected Bindable ControlPoint { get; } = new Bindable();
- private const float header_height = 20;
+ private const float header_height = 50;
[Resolved]
protected EditorBeatmap Beatmap { get; private set; }
@@ -35,7 +36,7 @@ namespace osu.Game.Screens.Edit.Timing
protected IEditorChangeHandler ChangeHandler { get; private set; }
[BackgroundDependencyLoader]
- private void load(OsuColour colours)
+ private void load(OverlayColourProvider colours)
{
RelativeSizeAxes = Axes.X;
AutoSizeDuration = 200;
@@ -46,19 +47,17 @@ namespace osu.Game.Screens.Edit.Timing
InternalChildren = new Drawable[]
{
- new Box
- {
- Colour = colours.Gray1,
- RelativeSizeAxes = Axes.Both,
- },
new Container
{
RelativeSizeAxes = Axes.X,
Height = header_height,
+ Padding = new MarginPadding { Horizontal = 10 },
Children = new Drawable[]
{
checkbox = new OsuCheckbox
{
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreLeft,
LabelText = typeof(T).Name.Replace(nameof(Beatmaps.ControlPoints.ControlPoint), string.Empty)
}
}
@@ -72,12 +71,13 @@ namespace osu.Game.Screens.Edit.Timing
{
new Box
{
- Colour = colours.Gray2,
+ Colour = colours.Background3,
RelativeSizeAxes = Axes.Both,
},
Flow = new FillFlowContainer
{
- Padding = new MarginPadding(10),
+ Padding = new MarginPadding(20),
+ Spacing = new Vector2(20),
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
diff --git a/osu.Game/Screens/Edit/Timing/TimingScreen.cs b/osu.Game/Screens/Edit/Timing/TimingScreen.cs
index c5d2dd756a..9f26dece08 100644
--- a/osu.Game/Screens/Edit/Timing/TimingScreen.cs
+++ b/osu.Game/Screens/Edit/Timing/TimingScreen.cs
@@ -8,15 +8,14 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps.ControlPoints;
-using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
-using osu.Game.Screens.Edit.Compose.Components.Timeline;
+using osu.Game.Overlays;
using osuTK;
namespace osu.Game.Screens.Edit.Timing
{
- public class TimingScreen : EditorScreenWithTimeline
+ public class TimingScreen : RoundedContentEditorScreen
{
[Cached]
private Bindable selectedGroup = new Bindable();
@@ -26,28 +25,26 @@ namespace osu.Game.Screens.Edit.Timing
{
}
- protected override Drawable CreateMainContent() => new GridContainer
+ [BackgroundDependencyLoader]
+ private void load()
{
- RelativeSizeAxes = Axes.Both,
- ColumnDimensions = new[]
+ Add(new GridContainer
{
- new Dimension(),
- new Dimension(GridSizeMode.Absolute, 200),
- },
- Content = new[]
- {
- new Drawable[]
+ RelativeSizeAxes = Axes.Both,
+ ColumnDimensions = new[]
{
- new ControlPointList(),
- new ControlPointSettings(),
+ new Dimension(),
+ new Dimension(GridSizeMode.Absolute, 350),
},
- }
- };
-
- protected override void OnTimelineLoaded(TimelineArea timelineArea)
- {
- base.OnTimelineLoaded(timelineArea);
- timelineArea.Timeline.Zoom = timelineArea.Timeline.MinZoom;
+ Content = new[]
+ {
+ new Drawable[]
+ {
+ new ControlPointList(),
+ new ControlPointSettings(),
+ },
+ }
+ });
}
public class ControlPointList : CompositeDrawable
@@ -70,17 +67,24 @@ namespace osu.Game.Screens.Edit.Timing
private IEditorChangeHandler changeHandler { get; set; }
[BackgroundDependencyLoader]
- private void load(OsuColour colours)
+ private void load(OverlayColourProvider colours)
{
RelativeSizeAxes = Axes.Both;
+ const float margins = 10;
InternalChildren = new Drawable[]
{
new Box
{
- Colour = colours.Gray0,
+ Colour = colours.Background3,
RelativeSizeAxes = Axes.Both,
},
+ new Box
+ {
+ Colour = colours.Background2,
+ RelativeSizeAxes = Axes.Y,
+ Width = ControlPointTable.TIMING_COLUMN_WIDTH + margins,
+ },
new OsuScrollContainer
{
RelativeSizeAxes = Axes.Both,
@@ -92,7 +96,7 @@ namespace osu.Game.Screens.Edit.Timing
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
Direction = FillDirection.Horizontal,
- Margin = new MarginPadding(10),
+ Margin = new MarginPadding(margins),
Spacing = new Vector2(5),
Children = new Drawable[]
{
@@ -106,9 +110,9 @@ namespace osu.Game.Screens.Edit.Timing
},
new OsuButton
{
- Text = "+",
+ Text = "+ Add at current time",
Action = addNew,
- Size = new Vector2(30, 30),
+ Size = new Vector2(160, 30),
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
},
diff --git a/osu.Game/Screens/Edit/Verify/VerifyScreen.cs b/osu.Game/Screens/Edit/Verify/VerifyScreen.cs
index 550fbe2950..a2ee153951 100644
--- a/osu.Game/Screens/Edit/Verify/VerifyScreen.cs
+++ b/osu.Game/Screens/Edit/Verify/VerifyScreen.cs
@@ -7,16 +7,16 @@ using osu.Framework.Bindables;
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.UserInterface;
+using osu.Game.Overlays;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Edit.Checks.Components;
using osuTK;
namespace osu.Game.Screens.Edit.Verify
{
- public class VerifyScreen : EditorScreen
+ public class VerifyScreen : RoundedContentEditorScreen
{
[Cached]
private Bindable selectedIssue = new Bindable();
@@ -32,7 +32,6 @@ namespace osu.Game.Screens.Edit.Verify
Child = new Container
{
RelativeSizeAxes = Axes.Both,
- Padding = new MarginPadding(20),
Child = new GridContainer
{
RelativeSizeAxes = Axes.Both,
@@ -70,7 +69,7 @@ namespace osu.Game.Screens.Edit.Verify
private BeatmapVerifier generalVerifier;
[BackgroundDependencyLoader]
- private void load(OsuColour colours)
+ private void load(OverlayColourProvider colours)
{
generalVerifier = new BeatmapVerifier();
rulesetVerifier = Beatmap.BeatmapInfo.Ruleset?.CreateInstance()?.CreateBeatmapVerifier();
@@ -81,7 +80,7 @@ namespace osu.Game.Screens.Edit.Verify
{
new Box
{
- Colour = colours.Gray0,
+ Colour = colours.Background2,
RelativeSizeAxes = Axes.Both,
},
new OsuScrollContainer
diff --git a/osu.Game/Skinning/PausableSkinnableSound.cs b/osu.Game/Skinning/PausableSkinnableSound.cs
index b3c7c5d6b2..10b8c47028 100644
--- a/osu.Game/Skinning/PausableSkinnableSound.cs
+++ b/osu.Game/Skinning/PausableSkinnableSound.cs
@@ -16,7 +16,7 @@ namespace osu.Game.Skinning
{
public double Length => !DrawableSamples.Any() ? 0 : DrawableSamples.Max(sample => sample.Length);
- protected bool RequestedPlaying { get; private set; }
+ public bool RequestedPlaying { get; private set; }
public PausableSkinnableSound()
{
diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardSample.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardSample.cs
index 7b16009859..fbdd27e762 100644
--- a/osu.Game/Storyboards/Drawables/DrawableStoryboardSample.cs
+++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardSample.cs
@@ -61,28 +61,32 @@ namespace osu.Game.Storyboards.Drawables
{
base.Update();
+ // Check if we've yet to pass the sample start time.
if (Time.Current < sampleInfo.StartTime)
{
- // We've rewound before the start time of the sample
Stop();
- // In the case that the user fast-forwards to a point far beyond the start time of the sample,
- // we want to be able to fall into the if-conditional below (therefore we must not have a life time end)
+ // Playback has stopped, but if the user fast-forwards to a point after the start time of the sample then
+ // we must not have a lifetime end in order to continue receiving updates and start the sample below.
LifetimeStart = sampleInfo.StartTime;
LifetimeEnd = double.MaxValue;
+
+ return;
}
- else if (Time.Current - Time.Elapsed <= sampleInfo.StartTime)
+
+ // Ensure that we've elapsed from a point before the sample's start time before playing.
+ if (Time.Current - Time.Elapsed <= sampleInfo.StartTime)
{
// We've passed the start time of the sample. We only play the sample if we're within an allowable range
// from the sample's start, to reduce layering if we've been fast-forwarded far into the future
if (!RequestedPlaying && Time.Current - sampleInfo.StartTime < allowable_late_start)
Play();
-
- // In the case that the user rewinds to a point far behind the start time of the sample,
- // we want to be able to fall into the if-conditional above (therefore we must not have a life time start)
- LifetimeStart = double.MinValue;
- LifetimeEnd = sampleInfo.StartTime;
}
+
+ // Playback has started, but if the user rewinds to a point before the start time of the sample then
+ // we must not have a lifetime start in order to continue receiving updates and stop the sample above.
+ LifetimeStart = double.MinValue;
+ LifetimeEnd = sampleInfo.StartTime;
}
}
}
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index e0a267241d..509cb3ddad 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -29,7 +29,7 @@
-
+
diff --git a/osu.iOS.props b/osu.iOS.props
index bcd953c0bd..4b67bd78a1 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -70,7 +70,7 @@
-
+
@@ -93,7 +93,7 @@
-
+