diff --git a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs index f2877572e8..dc3a4416a5 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs @@ -25,6 +25,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Edit { + // we're also a ScrollingHitObjectComposer candidate, but can't be everything can we? public partial class CatchHitObjectComposer : DistancedHitObjectComposer { private const float distance_snap_radius = 50; @@ -140,7 +141,7 @@ namespace osu.Game.Rulesets.Catch.Edit return base.OnPressed(e); } - protected override DrawableRuleset CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList? mods = null) => + protected override DrawableRuleset CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList mods) => new DrawableCatchEditorRuleset(ruleset, beatmap, mods) { TimeRangeMultiplier = { BindTarget = timeRangeMultiplier, } 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/Mods/TestSceneManiaModConstantSpeed.cs b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModConstantSpeed.cs index dc4f660a45..474430414c 100644 --- a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModConstantSpeed.cs +++ b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModConstantSpeed.cs @@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Mods PassCondition = () => { var hitObject = Player.ChildrenOfType().FirstOrDefault(); - return hitObject?.Dependencies.Get().Algorithm is ConstantScrollAlgorithm; + return hitObject?.Dependencies.Get().Algorithm.Value is ConstantScrollAlgorithm; } }); } 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 f480fa516b..7b019a2bdf 100644 --- a/osu.Game.Rulesets.Mania/Edit/DrawableManiaEditorRuleset.cs +++ b/osu.Game.Rulesets.Mania/Edit/DrawableManiaEditorRuleset.cs @@ -2,18 +2,22 @@ // 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.Rulesets.Mania.UI; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI.Scrolling; +using osuTK; namespace osu.Game.Rulesets.Mania.Edit { - public partial class DrawableManiaEditorRuleset : DrawableManiaRuleset + public partial class DrawableManiaEditorRuleset : DrawableManiaRuleset, ISupportConstantAlgorithmToggle { + public BindableBool ShowSpeedChanges { get; set; } = new BindableBool(); + public new IScrollingInfo ScrollingInfo => base.ScrollingInfo; public DrawableManiaEditorRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList? mods) @@ -21,6 +25,13 @@ namespace osu.Game.Rulesets.Mania.Edit { } + protected override void LoadComplete() + { + base.LoadComplete(); + + ShowSpeedChanges.BindValueChanged(showChanges => VisualisationMethod = showChanges.NewValue ? ScrollVisualisationMethod.Sequential : ScrollVisualisationMethod.Constant, true); + } + protected override Playfield CreatePlayfield() => new ManiaEditorPlayfield(Beatmap.Stages) { Anchor = Anchor.Centre, diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs index 5e577a2964..8e61baca81 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs @@ -21,7 +21,7 @@ using osuTK; namespace osu.Game.Rulesets.Mania.Edit { - public partial class ManiaHitObjectComposer : HitObjectComposer + public partial class ManiaHitObjectComposer : ScrollingHitObjectComposer { private DrawableManiaEditorRuleset drawableRuleset; private ManiaBeatSnapGrid beatSnapGrid; @@ -57,7 +57,7 @@ namespace osu.Game.Rulesets.Mania.Edit protected override Playfield PlayfieldAtScreenSpacePosition(Vector2 screenSpacePosition) => Playfield.GetColumnByPosition(screenSpacePosition); - protected override DrawableRuleset CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList mods = null) + protected override DrawableRuleset CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList mods) { drawableRuleset = new DrawableManiaEditorRuleset(ruleset, beatmap, mods); 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..9169599798 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; @@ -14,7 +13,6 @@ using osu.Framework.Graphics; using osu.Framework.Input; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Configuration; using osu.Game.Input.Handlers; using osu.Game.Replays; using osu.Game.Rulesets.Mania.Beatmaps; @@ -52,22 +50,6 @@ namespace osu.Game.Rulesets.Mania.UI protected new ManiaRulesetConfigManager Config => (ManiaRulesetConfigManager)base.Config; - public ScrollVisualisationMethod ScrollMethod - { - get => scrollMethod; - set - { - if (IsLoaded) - throw new InvalidOperationException($"Can't alter {nameof(ScrollMethod)} after ruleset is already loaded"); - - scrollMethod = 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.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index cff2171cbd..fdc11be42c 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Osu.Edit { } - protected override DrawableRuleset CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList mods = null) + protected override DrawableRuleset CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList mods) => new DrawableOsuEditorRuleset(ruleset, beatmap, mods); protected override IReadOnlyList CompositionTools => new HitObjectCompositionTool[] diff --git a/osu.Game.Rulesets.Taiko/Edit/DrawableTaikoEditorRuleset.cs b/osu.Game.Rulesets.Taiko/Edit/DrawableTaikoEditorRuleset.cs new file mode 100644 index 0000000000..963ddec0b3 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Edit/DrawableTaikoEditorRuleset.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.Bindables; +using osu.Game.Beatmaps; +using osu.Game.Configuration; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Taiko.UI; +using osu.Game.Rulesets.UI.Scrolling; + +namespace osu.Game.Rulesets.Taiko.Edit +{ + public partial class DrawableTaikoEditorRuleset : DrawableTaikoRuleset, ISupportConstantAlgorithmToggle + { + public BindableBool ShowSpeedChanges { get; set; } = new BindableBool(); + + public DrawableTaikoEditorRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList mods) + : base(ruleset, beatmap, mods) + { + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + ShowSpeedChanges.BindValueChanged(showChanges => VisualisationMethod = showChanges.NewValue ? ScrollVisualisationMethod.Overlapping : ScrollVisualisationMethod.Constant, true); + } + + protected override double ComputeTimeRange() + { + // Adjust when we're using constant algorithm to not be sluggish. + double multiplier = ShowSpeedChanges.Value ? 1 : 4; + return base.ComputeTimeRange() / multiplier; + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs b/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs index 3e63d624e7..5ae4757b8f 100644 --- a/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs +++ b/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs @@ -2,14 +2,17 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; +using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.UI; using osu.Game.Screens.Edit.Compose.Components; namespace osu.Game.Rulesets.Taiko.Edit { - public partial class TaikoHitObjectComposer : HitObjectComposer + public partial class TaikoHitObjectComposer : ScrollingHitObjectComposer { protected override bool ApplyHorizontalCentering => false; @@ -25,6 +28,9 @@ namespace osu.Game.Rulesets.Taiko.Edit new SwellCompositionTool() }; + protected override DrawableRuleset CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList mods) => + new DrawableTaikoEditorRuleset(ruleset, beatmap, mods); + protected override ComposeBlueprintContainer CreateBlueprintContainer() => new TaikoBlueprintContainer(this); } diff --git a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs index 64d406a308..2af4c0c2e8 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] @@ -65,6 +64,11 @@ namespace osu.Game.Rulesets.Taiko.UI { base.Update(); + TimeRange.Value = ComputeTimeRange(); + } + + protected virtual double ComputeTimeRange() + { // Taiko scrolls at a constant 100px per 1000ms. More notes become visible as the playfield is lengthened. const float scroll_rate = 10; @@ -73,7 +77,7 @@ namespace osu.Game.Rulesets.Taiko.UI // We clamp the ratio to the maximum aspect ratio to keep scroll speed consistent on widths lower than the default. float ratio = Math.Max(DrawSize.X / 768f, TaikoPlayfieldAdjustmentContainer.MAXIMUM_ASPECT); - TimeRange.Value = (Playfield.HitObjectContainer.DrawWidth / ratio) * scroll_rate; + return (Playfield.HitObjectContainer.DrawWidth / ratio) * scroll_rate; } protected override void UpdateAfterChildren() 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/Edit/DistancedHitObjectComposer.cs b/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs index e08cb41a26..70b79c30f0 100644 --- a/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs @@ -62,7 +62,7 @@ namespace osu.Game.Rulesets.Edit } [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) + private void load() { RightToolbox.Add(new EditorToolboxGroup("snapping") { diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index c967187b5c..f9a6b5083e 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -87,6 +87,8 @@ namespace osu.Game.Rulesets.Edit private IBindable hasTiming; private Bindable autoSeekOnPlacement; + protected DrawableRuleset DrawableRuleset { get; private set; } + protected HitObjectComposer(Ruleset ruleset) : base(ruleset) { @@ -104,7 +106,8 @@ namespace osu.Game.Rulesets.Edit try { - drawableRulesetWrapper = new DrawableEditorRulesetWrapper(CreateDrawableRuleset(Ruleset, EditorBeatmap.PlayableBeatmap, new[] { Ruleset.GetAutoplayMod() })) + DrawableRuleset = CreateDrawableRuleset(Ruleset, EditorBeatmap.PlayableBeatmap, new[] { Ruleset.GetAutoplayMod() }); + drawableRulesetWrapper = new DrawableEditorRulesetWrapper(DrawableRuleset) { Clock = EditorClock, ProcessCustomClock = false @@ -304,7 +307,7 @@ namespace osu.Game.Rulesets.Edit /// The loaded beatmap. /// The mods to be applied. /// An editor-relevant . - protected virtual DrawableRuleset CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList mods = null) + protected virtual DrawableRuleset CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList mods) => (DrawableRuleset)ruleset.CreateDrawableRulesetWith(beatmap, mods); #region Tool selection logic diff --git a/osu.Game/Rulesets/Edit/ScrollingHitObjectComposer.cs b/osu.Game/Rulesets/Edit/ScrollingHitObjectComposer.cs new file mode 100644 index 0000000000..75305a0c20 --- /dev/null +++ b/osu.Game/Rulesets/Edit/ScrollingHitObjectComposer.cs @@ -0,0 +1,51 @@ +// 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.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.UI.Scrolling; +using osu.Game.Screens.Edit.Components.TernaryButtons; +using osuTK; + +namespace osu.Game.Rulesets.Edit +{ + public abstract partial class ScrollingHitObjectComposer : HitObjectComposer + where TObject : HitObject + { + private readonly Bindable showSpeedChanges = new Bindable(); + + protected ScrollingHitObjectComposer(Ruleset ruleset) + : base(ruleset) + { + } + + [BackgroundDependencyLoader] + private void load() + { + if (DrawableRuleset is ISupportConstantAlgorithmToggle toggleRuleset) + { + 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 })) + } + }, + }); + + showSpeedChanges.BindValueChanged(state => toggleRuleset.ShowSpeedChanges.Value = state.NewValue == TernaryState.True, true); + } + } + } +} diff --git a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs index 4c7564b791..6abfc6ee49 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; + + public 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/ISupportConstantAlgorithmToggle.cs b/osu.Game/Rulesets/UI/Scrolling/ISupportConstantAlgorithmToggle.cs new file mode 100644 index 0000000000..aaa635350e --- /dev/null +++ b/osu.Game/Rulesets/UI/Scrolling/ISupportConstantAlgorithmToggle.cs @@ -0,0 +1,15 @@ +// 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; + +namespace osu.Game.Rulesets.UI.Scrolling +{ + /// + /// Denotes a which supports toggling constant algorithm for better display in the editor. + /// + public interface ISupportConstantAlgorithmToggle : IDrawableScrollingRuleset + { + public BindableBool ShowSpeedChanges { 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