From a2fd7707a16bccb055dd25997644173198851633 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 15 Aug 2023 20:38:17 +0900 Subject: [PATCH] Allow toggling SVs in the editor --- .../UI/DrawableCatchRuleset.cs | 3 +- .../Skinning/ManiaSkinnableTestScene.cs | 2 +- .../Edit/DrawableManiaEditorRuleset.cs | 17 ++++++- .../Edit/ManiaHitObjectComposer.cs | 28 +++++++++- .../Mods/ManiaModConstantSpeed.cs | 2 +- .../UI/DrawableManiaRuleset.cs | 17 ++----- .../UI/DrawableTaikoRuleset.cs | 3 +- .../TestSceneDrawableScrollingRuleset.cs | 3 +- .../UI/Scrolling/DrawableScrollingRuleset.cs | 51 ++++++++++++------- .../Rulesets/UI/Scrolling/IScrollingInfo.cs | 4 +- .../Scrolling/ScrollingHitObjectContainer.cs | 14 +++-- .../TernaryButtons/DrawableTernaryButton.cs | 2 +- .../Tests/Visual/ScrollingTestContainer.cs | 2 +- 13 files changed, 98 insertions(+), 50 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs index 7930a07551..f0a327d7ac 100644 --- a/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs @@ -21,8 +21,6 @@ namespace osu.Game.Rulesets.Catch.UI { public partial class DrawableCatchRuleset : DrawableScrollingRuleset { - protected override ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Constant; - protected override bool UserScrollSpeedAdjustment => false; public DrawableCatchRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList? mods = null) @@ -30,6 +28,7 @@ namespace osu.Game.Rulesets.Catch.UI { Direction.Value = ScrollingDirection.Down; TimeRange.Value = GetTimeRange(beatmap.Difficulty.ApproachRate); + VisualisationMethod = ScrollVisualisationMethod.Constant; } [BackgroundDependencyLoader] diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaSkinnableTestScene.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaSkinnableTestScene.cs index ba0c97a121..abf01aa4a4 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaSkinnableTestScene.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaSkinnableTestScene.cs @@ -58,7 +58,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning IBindable IScrollingInfo.Direction => Direction; IBindable IScrollingInfo.TimeRange { get; } = new Bindable(5000); - IScrollAlgorithm IScrollingInfo.Algorithm { get; } = new ConstantScrollAlgorithm(); + IBindable IScrollingInfo.Algorithm { get; } = new Bindable(new ConstantScrollAlgorithm()); } } } diff --git a/osu.Game.Rulesets.Mania/Edit/DrawableManiaEditorRuleset.cs b/osu.Game.Rulesets.Mania/Edit/DrawableManiaEditorRuleset.cs index dadd725a2f..013dd3dcbd 100644 --- a/osu.Game.Rulesets.Mania/Edit/DrawableManiaEditorRuleset.cs +++ b/osu.Game.Rulesets.Mania/Edit/DrawableManiaEditorRuleset.cs @@ -2,10 +2,12 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osuTK; using osu.Game.Beatmaps; using osu.Game.Configuration; +using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.UI; @@ -15,12 +17,25 @@ namespace osu.Game.Rulesets.Mania.Edit { public partial class DrawableManiaEditorRuleset : DrawableManiaRuleset { + public readonly IBindable ShowSpeedChanges = new Bindable(); + public new IScrollingInfo ScrollingInfo => base.ScrollingInfo; public DrawableManiaEditorRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList? mods) : base(ruleset, beatmap, mods) { - ScrollMethod = ScrollVisualisationMethod.Constant; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + ShowSpeedChanges.BindValueChanged(state => + { + VisualisationMethod = state.NewValue == TernaryState.True + ? ScrollVisualisationMethod.Sequential + : ScrollVisualisationMethod.Constant; + }, true); } protected override Playfield CreatePlayfield() => new ManiaEditorPlayfield(Beatmap.Stages) diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs index 5e577a2964..44e238efac 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs @@ -6,8 +6,13 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; using osu.Framework.Input; using osu.Game.Beatmaps; +using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Mania.Objects; @@ -16,6 +21,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI.Scrolling; +using osu.Game.Screens.Edit.Components.TernaryButtons; using osu.Game.Screens.Edit.Compose.Components; using osuTK; @@ -23,6 +29,8 @@ namespace osu.Game.Rulesets.Mania.Edit { public partial class ManiaHitObjectComposer : HitObjectComposer { + private readonly Bindable showSpeedChanges = new Bindable(); + private DrawableManiaEditorRuleset drawableRuleset; private ManiaBeatSnapGrid beatSnapGrid; private InputManager inputManager; @@ -36,6 +44,21 @@ namespace osu.Game.Rulesets.Mania.Edit private void load() { AddInternal(beatSnapGrid = new ManiaBeatSnapGrid()); + + LeftToolbox.Add(new EditorToolboxGroup("playfield") + { + Child = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 5), + Children = new[] + { + new DrawableTernaryButton(new TernaryButton(showSpeedChanges, "Show speed changes", () => new SpriteIcon { Icon = FontAwesome.Solid.TachometerAlt })) + } + }, + }); } protected override void LoadComplete() @@ -59,7 +82,10 @@ namespace osu.Game.Rulesets.Mania.Edit protected override DrawableRuleset CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList mods = null) { - drawableRuleset = new DrawableManiaEditorRuleset(ruleset, beatmap, mods); + drawableRuleset = new DrawableManiaEditorRuleset(ruleset, beatmap, mods) + { + ShowSpeedChanges = { BindTarget = showSpeedChanges } + }; // This is the earliest we can cache the scrolling info to ourselves, before masks are added to the hierarchy and inject it dependencies.CacheAs(drawableRuleset.ScrollingInfo); diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModConstantSpeed.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModConstantSpeed.cs index 66269f5572..d8e6bcd424 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModConstantSpeed.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModConstantSpeed.cs @@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Mania.Mods public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { var maniaRuleset = (DrawableManiaRuleset)drawableRuleset; - maniaRuleset.ScrollMethod = ScrollVisualisationMethod.Constant; + maniaRuleset.VisualisationMethod = ScrollVisualisationMethod.Constant; } } } diff --git a/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs b/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs index 2d373c0471..eb99434e04 100644 --- a/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs @@ -3,7 +3,6 @@ #nullable disable -using System; using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; @@ -52,22 +51,12 @@ namespace osu.Game.Rulesets.Mania.UI protected new ManiaRulesetConfigManager Config => (ManiaRulesetConfigManager)base.Config; - public ScrollVisualisationMethod ScrollMethod + public new ScrollVisualisationMethod VisualisationMethod { - get => scrollMethod; - set - { - if (IsLoaded) - throw new InvalidOperationException($"Can't alter {nameof(ScrollMethod)} after ruleset is already loaded"); - - scrollMethod = value; - } + get => base.VisualisationMethod; + set => base.VisualisationMethod = value; } - private ScrollVisualisationMethod scrollMethod = ScrollVisualisationMethod.Sequential; - - protected override ScrollVisualisationMethod VisualisationMethod => scrollMethod; - private readonly Bindable configDirection = new Bindable(); private readonly BindableInt configScrollSpeed = new BindableInt(); private double smoothTimeRange; diff --git a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs index 64d406a308..979e03f201 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs @@ -35,8 +35,6 @@ namespace osu.Game.Rulesets.Taiko.UI public new TaikoInputManager KeyBindingInputManager => (TaikoInputManager)base.KeyBindingInputManager; - protected override ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Overlapping; - protected override bool UserScrollSpeedAdjustment => false; private SkinnableDrawable scroller; @@ -45,6 +43,7 @@ namespace osu.Game.Rulesets.Taiko.UI : base(ruleset, beatmap, mods) { Direction.Value = ScrollingDirection.Left; + VisualisationMethod = ScrollVisualisationMethod.Overlapping; } [BackgroundDependencyLoader] diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs index 287b7d43b4..4c898feb48 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs @@ -311,14 +311,13 @@ namespace osu.Game.Tests.Visual.Gameplay protected override bool RelativeScaleBeatLengths => RelativeScaleBeatLengthsOverride; - protected override ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Overlapping; - public new Bindable TimeRange => base.TimeRange; public TestDrawableScrollingRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList mods = null) : base(ruleset, beatmap, mods) { TimeRange.Value = time_range; + VisualisationMethod = ScrollVisualisationMethod.Overlapping; } public override DrawableHitObject CreateDrawableRepresentation(TestHitObject h) diff --git a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs index 4c7564b791..d082d26792 100644 --- a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs +++ b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs @@ -64,8 +64,6 @@ namespace osu.Game.Rulesets.UI.Scrolling MaxValue = time_span_max }; - protected virtual ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Sequential; - ScrollVisualisationMethod IDrawableScrollingRuleset.VisualisationMethod => VisualisationMethod; /// @@ -99,20 +97,7 @@ namespace osu.Game.Rulesets.UI.Scrolling [BackgroundDependencyLoader] private void load() { - switch (VisualisationMethod) - { - case ScrollVisualisationMethod.Sequential: - scrollingInfo.Algorithm = new SequentialScrollAlgorithm(ControlPoints); - break; - - case ScrollVisualisationMethod.Overlapping: - scrollingInfo.Algorithm = new OverlappingScrollAlgorithm(ControlPoints); - break; - - case ScrollVisualisationMethod.Constant: - scrollingInfo.Algorithm = new ConstantScrollAlgorithm(); - break; - } + updateScrollAlgorithm(); double lastObjectTime = Beatmap.HitObjects.Any() ? Beatmap.GetLastObjectTime() : double.MaxValue; double baseBeatLength = TimingControlPoint.DEFAULT_BEAT_LENGTH; @@ -178,6 +163,36 @@ namespace osu.Game.Rulesets.UI.Scrolling throw new ArgumentException($"{nameof(Playfield)} must be a {nameof(ScrollingPlayfield)} when using {nameof(DrawableScrollingRuleset)}."); } + private ScrollVisualisationMethod visualisationMethod = ScrollVisualisationMethod.Sequential; + + protected ScrollVisualisationMethod VisualisationMethod + { + get => visualisationMethod; + set + { + visualisationMethod = value; + updateScrollAlgorithm(); + } + } + + private void updateScrollAlgorithm() + { + switch (VisualisationMethod) + { + case ScrollVisualisationMethod.Sequential: + scrollingInfo.Algorithm.Value = new SequentialScrollAlgorithm(ControlPoints); + break; + + case ScrollVisualisationMethod.Overlapping: + scrollingInfo.Algorithm.Value = new OverlappingScrollAlgorithm(ControlPoints); + break; + + case ScrollVisualisationMethod.Constant: + scrollingInfo.Algorithm.Value = new ConstantScrollAlgorithm(); + break; + } + } + /// /// Adjusts the scroll speed of s. /// @@ -217,7 +232,9 @@ namespace osu.Game.Rulesets.UI.Scrolling public IBindable TimeRange { get; } = new BindableDouble(); - public IScrollAlgorithm Algorithm { get; set; } + public readonly Bindable Algorithm = new Bindable(new ConstantScrollAlgorithm()); + + IBindable IScrollingInfo.Algorithm => Algorithm; } } } diff --git a/osu.Game/Rulesets/UI/Scrolling/IScrollingInfo.cs b/osu.Game/Rulesets/UI/Scrolling/IScrollingInfo.cs index cd85932599..4a79c1a447 100644 --- a/osu.Game/Rulesets/UI/Scrolling/IScrollingInfo.cs +++ b/osu.Game/Rulesets/UI/Scrolling/IScrollingInfo.cs @@ -15,13 +15,13 @@ namespace osu.Game.Rulesets.UI.Scrolling IBindable Direction { get; } /// - /// + /// The span of time that is visible by the length of the scrolling axes. /// IBindable TimeRange { get; } /// /// The algorithm which controls positions and sizes. /// - IScrollAlgorithm Algorithm { get; } + IBindable Algorithm { get; } } } diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index b93a427196..129918da14 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -13,6 +13,7 @@ using osu.Framework.Layout; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.UI.Scrolling.Algorithms; using osuTK; namespace osu.Game.Rulesets.UI.Scrolling @@ -21,6 +22,7 @@ namespace osu.Game.Rulesets.UI.Scrolling { private readonly IBindable timeRange = new BindableDouble(); private readonly IBindable direction = new Bindable(); + private readonly IBindable algorithm = new Bindable(); /// /// Whether the scrolling direction is horizontal or vertical. @@ -59,9 +61,11 @@ namespace osu.Game.Rulesets.UI.Scrolling { direction.BindTo(scrollingInfo.Direction); timeRange.BindTo(scrollingInfo.TimeRange); + algorithm.BindTo(scrollingInfo.Algorithm); direction.ValueChanged += _ => layoutCache.Invalidate(); timeRange.ValueChanged += _ => layoutCache.Invalidate(); + algorithm.ValueChanged += _ => layoutCache.Invalidate(); } /// @@ -73,7 +77,7 @@ namespace osu.Game.Rulesets.UI.Scrolling public double TimeAtPosition(float localPosition, double currentTime) { float scrollPosition = axisInverted ? -localPosition : localPosition; - return scrollingInfo.Algorithm.TimeAt(scrollPosition, currentTime, timeRange.Value, scrollLength); + return algorithm.Value.TimeAt(scrollPosition, currentTime, timeRange.Value, scrollLength); } /// @@ -95,7 +99,7 @@ namespace osu.Game.Rulesets.UI.Scrolling /// public float PositionAtTime(double time, double currentTime, double? originTime = null) { - float scrollPosition = scrollingInfo.Algorithm.PositionAt(time, currentTime, timeRange.Value, scrollLength, originTime); + float scrollPosition = algorithm.Value.PositionAt(time, currentTime, timeRange.Value, scrollLength, originTime); return axisInverted ? -scrollPosition : scrollPosition; } @@ -122,7 +126,7 @@ namespace osu.Game.Rulesets.UI.Scrolling /// public float LengthAtTime(double startTime, double endTime) { - return scrollingInfo.Algorithm.GetLength(startTime, endTime, timeRange.Value, scrollLength); + return algorithm.Value.GetLength(startTime, endTime, timeRange.Value, scrollLength); } private float scrollLength => scrollingAxis == Direction.Horizontal ? DrawWidth : DrawHeight; @@ -169,7 +173,7 @@ namespace osu.Game.Rulesets.UI.Scrolling foreach (var entry in Entries) setComputedLifetimeStart(entry); - scrollingInfo.Algorithm.Reset(); + algorithm.Value.Reset(); layoutCache.Validate(); } @@ -224,7 +228,7 @@ namespace osu.Game.Rulesets.UI.Scrolling break; } - return scrollingInfo.Algorithm.GetDisplayStartTime(entry.HitObject.StartTime, startOffset, timeRange.Value, scrollLength); + return algorithm.Value.GetDisplayStartTime(entry.HitObject.StartTime, startOffset, timeRange.Value, scrollLength); } private void setComputedLifetimeStart(HitObjectLifetimeEntry entry) diff --git a/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs b/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs index 873551db77..95d5dd36d8 100644 --- a/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs +++ b/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs @@ -14,7 +14,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Edit.Components.TernaryButtons { - internal partial class DrawableTernaryButton : OsuButton + public partial class DrawableTernaryButton : OsuButton { private Color4 defaultBackgroundColour; private Color4 defaultIconColour; diff --git a/osu.Game/Tests/Visual/ScrollingTestContainer.cs b/osu.Game/Tests/Visual/ScrollingTestContainer.cs index b8b39e16b5..bce4299688 100644 --- a/osu.Game/Tests/Visual/ScrollingTestContainer.cs +++ b/osu.Game/Tests/Visual/ScrollingTestContainer.cs @@ -58,7 +58,7 @@ namespace osu.Game.Tests.Visual IBindable IScrollingInfo.TimeRange => TimeRange; public readonly TestScrollAlgorithm Algorithm = new TestScrollAlgorithm(); - IScrollAlgorithm IScrollingInfo.Algorithm => Algorithm; + IBindable IScrollingInfo.Algorithm => new Bindable(Algorithm); } public class TestScrollAlgorithm : IScrollAlgorithm