From d26d4b8b79dcfcce739dd0723c1cf7fb3f959dd9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Oct 2023 16:42:22 +0900 Subject: [PATCH 01/10] Cache `IScrollingInfo` at a `HitObjectComposer` level automatically --- osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs | 9 +-------- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 3 +++ .../Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs | 2 +- .../Rulesets/UI/Scrolling/IDrawableScrollingRuleset.cs | 2 ++ 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs index 8e61baca81..7a0ec70611 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs @@ -57,16 +57,9 @@ 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) - { + protected override DrawableRuleset CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList mods) => drawableRuleset = new DrawableManiaEditorRuleset(ruleset, beatmap, mods); - // 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); - - return drawableRuleset; - } - protected override ComposeBlueprintContainer CreateBlueprintContainer() => new ManiaBlueprintContainer(this); diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index f9a6b5083e..e1ae4b0199 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -119,6 +119,9 @@ namespace osu.Game.Rulesets.Edit return; } + if (DrawableRuleset is IDrawableScrollingRuleset scrollingRuleset) + dependencies.CacheAs(scrollingRuleset.ScrollingInfo); + dependencies.CacheAs(Playfield); InternalChildren = new Drawable[] diff --git a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs index 6abfc6ee49..d23658ac33 100644 --- a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs +++ b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs @@ -81,7 +81,7 @@ namespace osu.Game.Rulesets.UI.Scrolling /// protected readonly SortedList ControlPoints = new SortedList(Comparer.Default); - protected IScrollingInfo ScrollingInfo => scrollingInfo; + public IScrollingInfo ScrollingInfo => scrollingInfo; [Cached(Type = typeof(IScrollingInfo))] private readonly LocalScrollingInfo scrollingInfo; diff --git a/osu.Game/Rulesets/UI/Scrolling/IDrawableScrollingRuleset.cs b/osu.Game/Rulesets/UI/Scrolling/IDrawableScrollingRuleset.cs index f3a3bb18bd..b348a22009 100644 --- a/osu.Game/Rulesets/UI/Scrolling/IDrawableScrollingRuleset.cs +++ b/osu.Game/Rulesets/UI/Scrolling/IDrawableScrollingRuleset.cs @@ -11,5 +11,7 @@ namespace osu.Game.Rulesets.UI.Scrolling public interface IDrawableScrollingRuleset { ScrollVisualisationMethod VisualisationMethod { get; } + + IScrollingInfo ScrollingInfo { get; } } } From 1b9acdf55c5cbeff194c4c80a3a26402ea64ab9d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Oct 2023 16:42:36 +0900 Subject: [PATCH 02/10] Abstract out common implementation of `BeatSnapGrid` --- .../Edit/CatchBeatSnapGrid.cs | 173 +-------------- .../Edit/ManiaBeatSnapGrid.cs | 197 +---------------- .../Edit/Compose/Components/BeatSnapGrid.cs | 203 ++++++++++++++++++ 3 files changed, 216 insertions(+), 357 deletions(-) create mode 100644 osu.Game/Screens/Edit/Compose/Components/BeatSnapGrid.cs diff --git a/osu.Game.Rulesets.Catch/Edit/CatchBeatSnapGrid.cs b/osu.Game.Rulesets.Catch/Edit/CatchBeatSnapGrid.cs index 6862696b3a..40bd08455f 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchBeatSnapGrid.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchBeatSnapGrid.cs @@ -1,180 +1,19 @@ // 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; -using osu.Framework.Caching; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Shapes; -using osu.Game.Graphics; +using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Objects; -using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Rulesets.UI.Scrolling; -using osu.Game.Screens.Edit; -using osuTK.Graphics; +using osu.Game.Screens.Edit.Compose.Components; namespace osu.Game.Rulesets.Catch.Edit { - /// - /// A grid which displays coloured beat divisor lines in proximity to the selection or placement cursor. - /// - /// - /// This class heavily borrows from osu!mania's implementation (ManiaBeatSnapGrid). - /// If further changes are to be made, they should also be applied there. - /// If the scale of the changes are large enough, abstracting may be a good path. - /// - public partial class CatchBeatSnapGrid : Component + public partial class CatchBeatSnapGrid : BeatSnapGrid { - private const double visible_range = 750; - - /// - /// The range of time values of the current selection. - /// - public (double start, double end)? SelectionTimeRange + protected override IEnumerable GetTargetContainers(HitObjectComposer composer) => new[] { - set - { - if (value == selectionTimeRange) - return; - - selectionTimeRange = value; - lineCache.Invalidate(); - } - } - - [Resolved] - private EditorBeatmap beatmap { get; set; } = null!; - - [Resolved] - private OsuColour colours { get; set; } = null!; - - [Resolved] - private BindableBeatDivisor beatDivisor { get; set; } = null!; - - private readonly Cached lineCache = new Cached(); - - private (double start, double end)? selectionTimeRange; - - private ScrollingHitObjectContainer lineContainer = null!; - - [BackgroundDependencyLoader] - private void load(HitObjectComposer composer) - { - lineContainer = new ScrollingHitObjectContainer(); - - ((CatchPlayfield)composer.Playfield).UnderlayElements.Add(lineContainer); - - beatDivisor.BindValueChanged(_ => createLines(), true); - } - - protected override void Update() - { - base.Update(); - - if (!lineCache.IsValid) - { - lineCache.Validate(); - createLines(); - } - } - - private readonly Stack availableLines = new Stack(); - - private void createLines() - { - foreach (var line in lineContainer.Objects.OfType()) - availableLines.Push(line); - - lineContainer.Clear(); - - if (selectionTimeRange == null) - return; - - var range = selectionTimeRange.Value; - - var timingPoint = beatmap.ControlPointInfo.TimingPointAt(range.start - visible_range); - - double time = timingPoint.Time; - int beat = 0; - - // progress time until in the visible range. - while (time < range.start - visible_range) - { - time += timingPoint.BeatLength / beatDivisor.Value; - beat++; - } - - while (time < range.end + visible_range) - { - var nextTimingPoint = beatmap.ControlPointInfo.TimingPointAt(time); - - // switch to the next timing point if we have reached it. - if (nextTimingPoint.Time > timingPoint.Time) - { - beat = 0; - time = nextTimingPoint.Time; - timingPoint = nextTimingPoint; - } - - Color4 colour = BindableBeatDivisor.GetColourFor( - BindableBeatDivisor.GetDivisorForBeatIndex(beat, beatDivisor.Value), colours); - - if (!availableLines.TryPop(out var line)) - line = new DrawableGridLine(); - - line.HitObject.StartTime = time; - line.Colour = colour; - - lineContainer.Add(line); - - beat++; - time += timingPoint.BeatLength / beatDivisor.Value; - } - - // required to update ScrollingHitObjectContainer's cache. - lineContainer.UpdateSubTree(); - - foreach (var line in lineContainer.Objects.OfType()) - { - time = line.HitObject.StartTime; - - if (time >= range.start && time <= range.end) - line.Alpha = 1; - else - { - double timeSeparation = time < range.start ? range.start - time : time - range.end; - line.Alpha = (float)Math.Max(0, 1 - timeSeparation / visible_range); - } - } - } - - private partial class DrawableGridLine : DrawableHitObject - { - public DrawableGridLine() - : base(new HitObject()) - { - RelativeSizeAxes = Axes.X; - Height = 2; - - AddInternal(new Box { RelativeSizeAxes = Axes.Both }); - } - - [BackgroundDependencyLoader] - private void load() - { - Origin = Anchor.BottomLeft; - Anchor = Anchor.BottomLeft; - } - - protected override void UpdateInitialTransforms() - { - // don't perform any fading – we are handling that ourselves. - LifetimeEnd = HitObject.StartTime + visible_range; - } - } + ((CatchPlayfield)composer.Playfield).UnderlayElements + }; } } diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaBeatSnapGrid.cs b/osu.Game.Rulesets.Mania/Edit/ManiaBeatSnapGrid.cs index 4d45e16588..61c730912f 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaBeatSnapGrid.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaBeatSnapGrid.cs @@ -1,206 +1,23 @@ // 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; -using osu.Framework.Bindables; -using osu.Framework.Caching; -using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Pooling; -using osu.Framework.Graphics.Shapes; -using osu.Game.Graphics; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Mania.UI; -using osu.Game.Rulesets.Objects; -using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Rulesets.UI.Scrolling; -using osu.Game.Screens.Edit; -using osuTK.Graphics; +using osu.Game.Screens.Edit.Compose.Components; namespace osu.Game.Rulesets.Mania.Edit { - /// - /// A grid which displays coloured beat divisor lines in proximity to the selection or placement cursor. - /// - public partial class ManiaBeatSnapGrid : CompositeComponent + public partial class ManiaBeatSnapGrid : BeatSnapGrid { - private const double visible_range = 750; - - /// - /// The range of time values of the current selection. - /// - public (double start, double end)? SelectionTimeRange + protected override IEnumerable GetTargetContainers(HitObjectComposer composer) { - set - { - if (value == selectionTimeRange) - return; - - selectionTimeRange = value; - lineCache.Invalidate(); - } - } - - [Resolved] - private EditorBeatmap beatmap { get; set; } = null!; - - [Resolved] - private OsuColour colours { get; set; } = null!; - - [Resolved] - private BindableBeatDivisor beatDivisor { get; set; } = null!; - - private readonly List grids = new List(); - - private readonly DrawablePool linesPool = new DrawablePool(50); - - private readonly Cached lineCache = new Cached(); - - private (double start, double end)? selectionTimeRange; - - [BackgroundDependencyLoader] - private void load(HitObjectComposer composer) - { - AddInternal(linesPool); - - foreach (var stage in ((ManiaPlayfield)composer.Playfield).Stages) - { - foreach (var column in stage.Columns) - { - var lineContainer = new ScrollingHitObjectContainer(); - - grids.Add(lineContainer); - column.UnderlayElements.Add(lineContainer); - } - } - - beatDivisor.BindValueChanged(_ => createLines(), true); - } - - protected override void Update() - { - base.Update(); - - if (!lineCache.IsValid) - { - lineCache.Validate(); - createLines(); - } - } - - private void createLines() - { - foreach (var grid in grids) - grid.Clear(); - - if (selectionTimeRange == null) - return; - - var range = selectionTimeRange.Value; - - var timingPoint = beatmap.ControlPointInfo.TimingPointAt(range.start - visible_range); - - double time = timingPoint.Time; - int beat = 0; - - // progress time until in the visible range. - while (time < range.start - visible_range) - { - time += timingPoint.BeatLength / beatDivisor.Value; - beat++; - } - - while (time < range.end + visible_range) - { - var nextTimingPoint = beatmap.ControlPointInfo.TimingPointAt(time); - - // switch to the next timing point if we have reached it. - if (nextTimingPoint.Time > timingPoint.Time) - { - beat = 0; - time = nextTimingPoint.Time; - timingPoint = nextTimingPoint; - } - - Color4 colour = BindableBeatDivisor.GetColourFor( - BindableBeatDivisor.GetDivisorForBeatIndex(beat, beatDivisor.Value), colours); - - foreach (var grid in grids) - { - var line = linesPool.Get(); - - line.Apply(new HitObject - { - StartTime = time - }); - - line.Colour = colour; - - grid.Add(line); - } - - beat++; - time += timingPoint.BeatLength / beatDivisor.Value; - } - - foreach (var grid in grids) - { - // required to update ScrollingHitObjectContainer's cache. - grid.UpdateSubTree(); - - foreach (var line in grid.Objects.OfType()) - { - time = line.HitObject.StartTime; - - if (time >= range.start && time <= range.end) - line.Alpha = 1; - else - { - double timeSeparation = time < range.start ? range.start - time : time - range.end; - line.Alpha = (float)Math.Max(0, 1 - timeSeparation / visible_range); - } - } - } - } - - private partial class DrawableGridLine : DrawableHitObject - { - [Resolved] - private IScrollingInfo scrollingInfo { get; set; } = null!; - - private readonly IBindable direction = new Bindable(); - - public DrawableGridLine() - : base(new HitObject()) - { - RelativeSizeAxes = Axes.X; - Height = 2; - - AddInternal(new Box { RelativeSizeAxes = Axes.Both }); - } - - [BackgroundDependencyLoader] - private void load() - { - direction.BindTo(scrollingInfo.Direction); - direction.BindValueChanged(onDirectionChanged, true); - } - - private void onDirectionChanged(ValueChangedEvent direction) - { - Origin = Anchor = direction.NewValue == ScrollingDirection.Up - ? Anchor.TopLeft - : Anchor.BottomLeft; - } - - protected override void UpdateInitialTransforms() - { - // don't perform any fading – we are handling that ourselves. - LifetimeEnd = HitObject.StartTime + visible_range; - } + return ((ManiaPlayfield)composer.Playfield) + .Stages + .SelectMany(stage => stage.Columns) + .Select(column => column.UnderlayElements); } } } diff --git a/osu.Game/Screens/Edit/Compose/Components/BeatSnapGrid.cs b/osu.Game/Screens/Edit/Compose/Components/BeatSnapGrid.cs new file mode 100644 index 0000000000..c7adaa5649 --- /dev/null +++ b/osu.Game/Screens/Edit/Compose/Components/BeatSnapGrid.cs @@ -0,0 +1,203 @@ +// 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; +using osu.Framework.Bindables; +using osu.Framework.Caching; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Pooling; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.UI.Scrolling; +using osuTK.Graphics; + +namespace osu.Game.Screens.Edit.Compose.Components +{ + /// + /// A grid which displays coloured beat divisor lines in proximity to the selection or placement cursor. + /// + public abstract partial class BeatSnapGrid : CompositeComponent + { + private const double visible_range = 750; + + /// + /// The range of time values of the current selection. + /// + public (double start, double end)? SelectionTimeRange + { + set + { + if (value == selectionTimeRange) + return; + + selectionTimeRange = value; + lineCache.Invalidate(); + } + } + + [Resolved] + private EditorBeatmap beatmap { get; set; } = null!; + + [Resolved] + private OsuColour colours { get; set; } = null!; + + [Resolved] + private BindableBeatDivisor beatDivisor { get; set; } = null!; + + private readonly List grids = new List(); + + private readonly DrawablePool linesPool = new DrawablePool(50); + + private readonly Cached lineCache = new Cached(); + + private (double start, double end)? selectionTimeRange; + + [BackgroundDependencyLoader] + private void load(HitObjectComposer composer) + { + AddInternal(linesPool); + + foreach (var target in GetTargetContainers(composer)) + { + var lineContainer = new ScrollingHitObjectContainer(); + + grids.Add(lineContainer); + target.Add(lineContainer); + } + + beatDivisor.BindValueChanged(_ => createLines(), true); + } + + protected abstract IEnumerable GetTargetContainers(HitObjectComposer composer); + + protected override void Update() + { + base.Update(); + + if (!lineCache.IsValid) + { + lineCache.Validate(); + createLines(); + } + } + + private void createLines() + { + foreach (var grid in grids) + grid.Clear(); + + if (selectionTimeRange == null) + return; + + var range = selectionTimeRange.Value; + + var timingPoint = beatmap.ControlPointInfo.TimingPointAt(range.start - visible_range); + + double time = timingPoint.Time; + int beat = 0; + + // progress time until in the visible range. + while (time < range.start - visible_range) + { + time += timingPoint.BeatLength / beatDivisor.Value; + beat++; + } + + while (time < range.end + visible_range) + { + var nextTimingPoint = beatmap.ControlPointInfo.TimingPointAt(time); + + // switch to the next timing point if we have reached it. + if (nextTimingPoint.Time > timingPoint.Time) + { + beat = 0; + time = nextTimingPoint.Time; + timingPoint = nextTimingPoint; + } + + Color4 colour = BindableBeatDivisor.GetColourFor( + BindableBeatDivisor.GetDivisorForBeatIndex(beat, beatDivisor.Value), colours); + + foreach (var grid in grids) + { + var line = linesPool.Get(); + + line.Apply(new HitObject + { + StartTime = time + }); + + line.Colour = colour; + + grid.Add(line); + } + + beat++; + time += timingPoint.BeatLength / beatDivisor.Value; + } + + foreach (var grid in grids) + { + // required to update ScrollingHitObjectContainer's cache. + grid.UpdateSubTree(); + + foreach (var line in grid.Objects.OfType()) + { + time = line.HitObject.StartTime; + + if (time >= range.start && time <= range.end) + line.Alpha = 1; + else + { + double timeSeparation = time < range.start ? range.start - time : time - range.end; + line.Alpha = (float)Math.Max(0, 1 - timeSeparation / visible_range); + } + } + } + } + + private partial class DrawableGridLine : DrawableHitObject + { + [Resolved] + private IScrollingInfo scrollingInfo { get; set; } = null!; + + private readonly IBindable direction = new Bindable(); + + public DrawableGridLine() + : base(new HitObject()) + { + RelativeSizeAxes = Axes.X; + Height = 2; + + AddInternal(new Box { RelativeSizeAxes = Axes.Both }); + } + + [BackgroundDependencyLoader] + private void load() + { + direction.BindTo(scrollingInfo.Direction); + direction.BindValueChanged(onDirectionChanged, true); + } + + private void onDirectionChanged(ValueChangedEvent direction) + { + Origin = Anchor = direction.NewValue == ScrollingDirection.Up + ? Anchor.TopLeft + : Anchor.BottomLeft; + } + + protected override void UpdateInitialTransforms() + { + // don't perform any fading – we are handling that ourselves. + LifetimeEnd = HitObject.StartTime + visible_range; + } + } + } +} From 2a89a257909712e79fff9578bfc5821016dacf66 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Oct 2023 16:54:59 +0900 Subject: [PATCH 03/10] Add beat snap grid to osu!taiko editor Addresses https://github.com/ppy/osu/discussions/25150. --- .../Edit/TaikoBeatSnapGrid.cs | 19 ++++++++ .../Edit/TaikoHitObjectComposer.cs | 43 +++++++++++++++++++ osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 11 ++++- .../Edit/Compose/Components/BeatSnapGrid.cs | 16 +++++-- 4 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 osu.Game.Rulesets.Taiko/Edit/TaikoBeatSnapGrid.cs diff --git a/osu.Game.Rulesets.Taiko/Edit/TaikoBeatSnapGrid.cs b/osu.Game.Rulesets.Taiko/Edit/TaikoBeatSnapGrid.cs new file mode 100644 index 0000000000..1b6794974f --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Edit/TaikoBeatSnapGrid.cs @@ -0,0 +1,19 @@ +// 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.Graphics.Containers; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Taiko.UI; +using osu.Game.Screens.Edit.Compose.Components; + +namespace osu.Game.Rulesets.Taiko.Edit +{ + public partial class TaikoBeatSnapGrid : BeatSnapGrid + { + protected override IEnumerable GetTargetContainers(HitObjectComposer composer) => new[] + { + ((TaikoPlayfield)composer.Playfield).UnderlayElements + }; + } +} diff --git a/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs b/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs index 5ae4757b8f..177f548238 100644 --- a/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs +++ b/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs @@ -2,10 +2,14 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Input; using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.UI; using osu.Game.Screens.Edit.Compose.Components; @@ -16,6 +20,9 @@ namespace osu.Game.Rulesets.Taiko.Edit { protected override bool ApplyHorizontalCentering => false; + private TaikoBeatSnapGrid beatSnapGrid = null!; + private InputManager inputManager = null!; + public TaikoHitObjectComposer(TaikoRuleset ruleset) : base(ruleset) { @@ -33,5 +40,41 @@ namespace osu.Game.Rulesets.Taiko.Edit protected override ComposeBlueprintContainer CreateBlueprintContainer() => new TaikoBlueprintContainer(this); + + [BackgroundDependencyLoader] + private void load() + { + AddInternal(beatSnapGrid = new TaikoBeatSnapGrid()); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + inputManager = GetContainingInputManager(); + } + + protected override void UpdateAfterChildren() + { + base.UpdateAfterChildren(); + + if (BlueprintContainer.CurrentTool is SelectTool) + { + if (EditorBeatmap.SelectedHitObjects.Any()) + { + beatSnapGrid.SelectionTimeRange = (EditorBeatmap.SelectedHitObjects.Min(h => h.StartTime), EditorBeatmap.SelectedHitObjects.Max(h => h.GetEndTime())); + } + else + beatSnapGrid.SelectionTimeRange = null; + } + else + { + var result = FindSnappedPositionAndTime(inputManager.CurrentState.Mouse.Position); + if (result.Time is double time) + beatSnapGrid.SelectionTimeRange = (time, time); + else + beatSnapGrid.SelectionTimeRange = null; + } + } } } diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 23ffac1f63..31f8171290 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -40,6 +40,8 @@ namespace osu.Game.Rulesets.Taiko.UI /// public Bindable ClassicHitTargetPosition = new BindableBool(); + public Container UnderlayElements { get; private set; } = null!; + private Container hitExplosionContainer; private Container kiaiExplosionContainer; private JudgementContainer judgementContainer; @@ -130,7 +132,14 @@ namespace osu.Game.Rulesets.Taiko.UI { Name = "Bar line content", RelativeSizeAxes = Axes.Both, - Child = barLinePlayfield = new BarLinePlayfield(), + Children = new Drawable[] + { + UnderlayElements = new Container + { + RelativeSizeAxes = Axes.Both, + }, + barLinePlayfield = new BarLinePlayfield(), + } }, hitObjectContent = new Container { diff --git a/osu.Game/Screens/Edit/Compose/Components/BeatSnapGrid.cs b/osu.Game/Screens/Edit/Compose/Components/BeatSnapGrid.cs index c7adaa5649..766d5b5601 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BeatSnapGrid.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BeatSnapGrid.cs @@ -173,9 +173,6 @@ namespace osu.Game.Screens.Edit.Compose.Components public DrawableGridLine() : base(new HitObject()) { - RelativeSizeAxes = Axes.X; - Height = 2; - AddInternal(new Box { RelativeSizeAxes = Axes.Both }); } @@ -191,6 +188,19 @@ namespace osu.Game.Screens.Edit.Compose.Components Origin = Anchor = direction.NewValue == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; + + bool isHorizontal = direction.NewValue == ScrollingDirection.Left || direction.NewValue == ScrollingDirection.Right; + + if (isHorizontal) + { + RelativeSizeAxes = Axes.Y; + Width = 2; + } + else + { + RelativeSizeAxes = Axes.X; + Height = 2; + } } protected override void UpdateInitialTransforms() From 4381169a3fdf582414f82c0c0d3af52d85404ae6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Oct 2023 17:09:42 +0900 Subject: [PATCH 04/10] Combine selection and input handling logic for beat snap grids across all rulesets --- .../Edit/CatchHitObjectComposer.cs | 41 ++------------- .../Edit/ManiaHitObjectComposer.cs | 42 +-------------- .../Edit/TaikoHitObjectComposer.cs | 43 +--------------- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 51 +++++++++++++++++-- 4 files changed, 53 insertions(+), 124 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs index dc3a4416a5..80a9731cc4 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs @@ -8,7 +8,6 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Graphics; -using osu.Framework.Input; using osu.Framework.Input.Events; using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterface; @@ -32,10 +31,6 @@ namespace osu.Game.Rulesets.Catch.Edit private CatchDistanceSnapGrid distanceSnapGrid = null!; - private InputManager inputManager = null!; - - private CatchBeatSnapGrid beatSnapGrid = null!; - private readonly BindableDouble timeRangeMultiplier = new BindableDouble(1) { MinValue = 1, @@ -68,38 +63,6 @@ namespace osu.Game.Rulesets.Catch.Edit Catcher.BASE_DASH_SPEED, -Catcher.BASE_DASH_SPEED, Catcher.BASE_WALK_SPEED, -Catcher.BASE_WALK_SPEED, })); - - AddInternal(beatSnapGrid = new CatchBeatSnapGrid()); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - inputManager = GetContainingInputManager(); - } - - protected override void UpdateAfterChildren() - { - base.UpdateAfterChildren(); - - if (BlueprintContainer.CurrentTool is SelectTool) - { - if (EditorBeatmap.SelectedHitObjects.Any()) - { - beatSnapGrid.SelectionTimeRange = (EditorBeatmap.SelectedHitObjects.Min(h => h.StartTime), EditorBeatmap.SelectedHitObjects.Max(h => h.GetEndTime())); - } - else - beatSnapGrid.SelectionTimeRange = null; - } - else - { - var result = FindSnappedPositionAndTime(inputManager.CurrentState.Mouse.Position); - if (result.Time is double time) - beatSnapGrid.SelectionTimeRange = (time, time); - else - beatSnapGrid.SelectionTimeRange = null; - } } protected override double ReadCurrentDistanceSnap(HitObject before, HitObject after) @@ -174,6 +137,8 @@ namespace osu.Game.Rulesets.Catch.Edit protected override ComposeBlueprintContainer CreateBlueprintContainer() => new CatchBlueprintContainer(this); + protected override BeatSnapGrid CreateBeatSnapGrid() => new CatchBeatSnapGrid(); + private PalpableCatchHitObject? getLastSnappableHitObject(double time) { var hitObject = EditorBeatmap.HitObjects.OfType().LastOrDefault(h => h.GetEndTime() < time && !(h is BananaShower)); @@ -214,7 +179,7 @@ namespace osu.Game.Rulesets.Catch.Edit return null; } - double timeAtCursor = ((CatchPlayfield)Playfield).TimeAtScreenSpacePosition(inputManager.CurrentState.Mouse.Position); + double timeAtCursor = ((CatchPlayfield)Playfield).TimeAtScreenSpacePosition(InputManager.CurrentState.Mouse.Position); return getLastSnappableHitObject(timeAtCursor); default: diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs index 7a0ec70611..91fe99f938 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs @@ -6,14 +6,12 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; -using osu.Framework.Input; using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.UI; 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.Compose.Components; @@ -24,27 +22,12 @@ namespace osu.Game.Rulesets.Mania.Edit public partial class ManiaHitObjectComposer : ScrollingHitObjectComposer { private DrawableManiaEditorRuleset drawableRuleset; - private ManiaBeatSnapGrid beatSnapGrid; - private InputManager inputManager; public ManiaHitObjectComposer(Ruleset ruleset) : base(ruleset) { } - [BackgroundDependencyLoader] - private void load() - { - AddInternal(beatSnapGrid = new ManiaBeatSnapGrid()); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - inputManager = GetContainingInputManager(); - } - private DependencyContainer dependencies; protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) @@ -63,35 +46,14 @@ namespace osu.Game.Rulesets.Mania.Edit protected override ComposeBlueprintContainer CreateBlueprintContainer() => new ManiaBlueprintContainer(this); + protected override BeatSnapGrid CreateBeatSnapGrid() => new ManiaBeatSnapGrid(); + protected override IReadOnlyList CompositionTools => new HitObjectCompositionTool[] { new NoteCompositionTool(), new HoldNoteCompositionTool() }; - protected override void UpdateAfterChildren() - { - base.UpdateAfterChildren(); - - if (BlueprintContainer.CurrentTool is SelectTool) - { - if (EditorBeatmap.SelectedHitObjects.Any()) - { - beatSnapGrid.SelectionTimeRange = (EditorBeatmap.SelectedHitObjects.Min(h => h.StartTime), EditorBeatmap.SelectedHitObjects.Max(h => h.GetEndTime())); - } - else - beatSnapGrid.SelectionTimeRange = null; - } - else - { - var result = FindSnappedPositionAndTime(inputManager.CurrentState.Mouse.Position); - if (result.Time is double time) - beatSnapGrid.SelectionTimeRange = (time, time); - else - beatSnapGrid.SelectionTimeRange = null; - } - } - public override string ConvertSelectionToString() => string.Join(',', EditorBeatmap.SelectedHitObjects.Cast().OrderBy(h => h.StartTime).Select(h => $"{h.StartTime}|{h.Column}")); } diff --git a/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs b/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs index 177f548238..6020f6e04c 100644 --- a/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs +++ b/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs @@ -2,14 +2,10 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; -using System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Input; using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.UI; using osu.Game.Screens.Edit.Compose.Components; @@ -20,9 +16,6 @@ namespace osu.Game.Rulesets.Taiko.Edit { protected override bool ApplyHorizontalCentering => false; - private TaikoBeatSnapGrid beatSnapGrid = null!; - private InputManager inputManager = null!; - public TaikoHitObjectComposer(TaikoRuleset ruleset) : base(ruleset) { @@ -41,40 +34,6 @@ namespace osu.Game.Rulesets.Taiko.Edit protected override ComposeBlueprintContainer CreateBlueprintContainer() => new TaikoBlueprintContainer(this); - [BackgroundDependencyLoader] - private void load() - { - AddInternal(beatSnapGrid = new TaikoBeatSnapGrid()); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - inputManager = GetContainingInputManager(); - } - - protected override void UpdateAfterChildren() - { - base.UpdateAfterChildren(); - - if (BlueprintContainer.CurrentTool is SelectTool) - { - if (EditorBeatmap.SelectedHitObjects.Any()) - { - beatSnapGrid.SelectionTimeRange = (EditorBeatmap.SelectedHitObjects.Min(h => h.StartTime), EditorBeatmap.SelectedHitObjects.Max(h => h.GetEndTime())); - } - else - beatSnapGrid.SelectionTimeRange = null; - } - else - { - var result = FindSnappedPositionAndTime(inputManager.CurrentState.Mouse.Position); - if (result.Time is double time) - beatSnapGrid.SelectionTimeRange = (time, time); - else - beatSnapGrid.SelectionTimeRange = null; - } - } + protected override BeatSnapGrid CreateBeatSnapGrid() => new TaikoBeatSnapGrid(); } } diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index e1ae4b0199..2a859dad0d 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; +using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.EnumExtensions; @@ -76,7 +77,7 @@ namespace osu.Game.Rulesets.Edit protected readonly Container LayerBelowRuleset = new Container { RelativeSizeAxes = Axes.Both }; - private InputManager inputManager; + protected InputManager InputManager { get; private set; } private EditorRadioButtonCollection toolboxCollection; @@ -89,6 +90,9 @@ namespace osu.Game.Rulesets.Edit protected DrawableRuleset DrawableRuleset { get; private set; } + [CanBeNull] + private BeatSnapGrid beatSnapGrid; + protected HitObjectComposer(Ruleset ruleset) : base(ruleset) { @@ -204,7 +208,9 @@ namespace osu.Game.Rulesets.Edit }, } } - } + }, + // Must be constructed after drawable ruleset above. + (beatSnapGrid = CreateBeatSnapGrid()) ?? Empty(), }; toolboxCollection.Items = CompositionTools @@ -235,7 +241,7 @@ namespace osu.Game.Rulesets.Edit { base.LoadComplete(); - inputManager = GetContainingInputManager(); + InputManager = GetContainingInputManager(); hasTiming = EditorBeatmap.HasTiming.GetBoundCopy(); hasTiming.BindValueChanged(timing => @@ -269,11 +275,42 @@ namespace osu.Game.Rulesets.Edit } } + protected override void UpdateAfterChildren() + { + base.UpdateAfterChildren(); + + updateBeatSnapGrid(); + } + + private void updateBeatSnapGrid() + { + if (beatSnapGrid == null) + return; + + if (BlueprintContainer.CurrentTool is SelectTool) + { + if (EditorBeatmap.SelectedHitObjects.Any()) + { + beatSnapGrid.SelectionTimeRange = (EditorBeatmap.SelectedHitObjects.Min(h => h.StartTime), EditorBeatmap.SelectedHitObjects.Max(h => h.GetEndTime())); + } + else + beatSnapGrid.SelectionTimeRange = null; + } + else + { + var result = FindSnappedPositionAndTime(InputManager.CurrentState.Mouse.Position); + if (result.Time is double time) + beatSnapGrid.SelectionTimeRange = (time, time); + else + beatSnapGrid.SelectionTimeRange = null; + } + } + public override Playfield Playfield => drawableRulesetWrapper.Playfield; public override IEnumerable HitObjects => drawableRulesetWrapper.Playfield.AllHitObjects; - public override bool CursorInPlacementArea => drawableRulesetWrapper.Playfield.ReceivePositionalInputAt(inputManager.CurrentState.Mouse.Position); + public override bool CursorInPlacementArea => drawableRulesetWrapper.Playfield.ReceivePositionalInputAt(InputManager.CurrentState.Mouse.Position); /// /// Defines all available composition tools, listed on the left side of the editor screen as button controls. @@ -299,6 +336,12 @@ namespace osu.Game.Rulesets.Edit /// protected virtual ComposeBlueprintContainer CreateBlueprintContainer() => new ComposeBlueprintContainer(this); + /// + /// Construct an optional beat snap grid. + /// + [CanBeNull] + protected virtual BeatSnapGrid CreateBeatSnapGrid() => null; + /// /// Construct a drawable ruleset for the provided ruleset. /// From 7abd7fe658e51753a7ebc54f91d0ab042b5f7efb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 17 Oct 2023 10:26:02 +0200 Subject: [PATCH 05/10] Remove redundant explicit array type specification --- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 2a859dad0d..129ab6751e 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -128,7 +128,7 @@ namespace osu.Game.Rulesets.Edit dependencies.CacheAs(Playfield); - InternalChildren = new Drawable[] + InternalChildren = new[] { PlayfieldContentContainer = new Container { From 22c1a963e722d4ce62cb24df907974fc1284d42f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 17 Oct 2023 10:27:16 +0200 Subject: [PATCH 06/10] Remove unused field --- osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs index 91fe99f938..61ddaffb25 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs @@ -28,11 +28,6 @@ namespace osu.Game.Rulesets.Mania.Edit { } - private DependencyContainer dependencies; - - protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) - => dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); - public new ManiaPlayfield Playfield => ((ManiaPlayfield)drawableRuleset.Playfield); public IScrollingInfo ScrollingInfo => drawableRuleset.ScrollingInfo; From 2192c9f2c28e5a34cc753f62218a19026c21755c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 17 Oct 2023 10:30:01 +0200 Subject: [PATCH 07/10] Remove unused using directive --- osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs index 61ddaffb25..b9db4168f4 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Linq; -using osu.Framework.Allocation; using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; From 013b5fa916d819ec7a8a93b1692d4aa027934a67 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Oct 2023 23:54:34 +0900 Subject: [PATCH 08/10] Move beat snap grid implementation details to `ScrollingHitObjectComposer` --- .../Edit/CatchHitObjectComposer.cs | 34 -------------- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 42 ----------------- .../Edit/ScrollingHitObjectComposer.cs | 46 +++++++++++++++++++ 3 files changed, 46 insertions(+), 76 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs index 2ccf99c6e6..9b258841b2 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs @@ -40,8 +40,6 @@ namespace osu.Game.Rulesets.Catch.Edit [Cached(typeof(IDistanceSnapProvider))] protected readonly CatchDistanceSnapProvider DistanceSnapProvider = new CatchDistanceSnapProvider(); - private BeatSnapGrid beatSnapGrid = null!; - public CatchHitObjectComposer(CatchRuleset ruleset) : base(ruleset) { @@ -71,44 +69,12 @@ namespace osu.Game.Rulesets.Catch.Edit Catcher.BASE_DASH_SPEED, -Catcher.BASE_DASH_SPEED, Catcher.BASE_WALK_SPEED, -Catcher.BASE_WALK_SPEED, })); - - AddInternal(beatSnapGrid = new CatchBeatSnapGrid()); } protected override IEnumerable CreateTernaryButtons() => base.CreateTernaryButtons() .Concat(DistanceSnapProvider.CreateTernaryButtons()); - protected override void UpdateAfterChildren() - { - base.UpdateAfterChildren(); - - if (BlueprintContainer.CurrentTool is SelectTool) - { - if (EditorBeatmap.SelectedHitObjects.Any()) - { - beatSnapGrid.SelectionTimeRange = (EditorBeatmap.SelectedHitObjects.Min(h => h.StartTime), EditorBeatmap.SelectedHitObjects.Max(h => h.GetEndTime())); - } - else - beatSnapGrid.SelectionTimeRange = null; - } - else - { - var result = FindSnappedPositionAndTime(InputManager.CurrentState.Mouse.Position); - if (result.Time is double time) - beatSnapGrid.SelectionTimeRange = (time, time); - else - beatSnapGrid.SelectionTimeRange = null; - } - } - - protected override void Update() - { - base.Update(); - - updateDistanceSnapGrid(); - } - public bool OnPressed(KeyBindingPressEvent e) { switch (e.Action) diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 129ab6751e..b68af49222 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -90,9 +90,6 @@ namespace osu.Game.Rulesets.Edit protected DrawableRuleset DrawableRuleset { get; private set; } - [CanBeNull] - private BeatSnapGrid beatSnapGrid; - protected HitObjectComposer(Ruleset ruleset) : base(ruleset) { @@ -209,8 +206,6 @@ namespace osu.Game.Rulesets.Edit } } }, - // Must be constructed after drawable ruleset above. - (beatSnapGrid = CreateBeatSnapGrid()) ?? Empty(), }; toolboxCollection.Items = CompositionTools @@ -275,37 +270,6 @@ namespace osu.Game.Rulesets.Edit } } - protected override void UpdateAfterChildren() - { - base.UpdateAfterChildren(); - - updateBeatSnapGrid(); - } - - private void updateBeatSnapGrid() - { - if (beatSnapGrid == null) - return; - - if (BlueprintContainer.CurrentTool is SelectTool) - { - if (EditorBeatmap.SelectedHitObjects.Any()) - { - beatSnapGrid.SelectionTimeRange = (EditorBeatmap.SelectedHitObjects.Min(h => h.StartTime), EditorBeatmap.SelectedHitObjects.Max(h => h.GetEndTime())); - } - else - beatSnapGrid.SelectionTimeRange = null; - } - else - { - var result = FindSnappedPositionAndTime(InputManager.CurrentState.Mouse.Position); - if (result.Time is double time) - beatSnapGrid.SelectionTimeRange = (time, time); - else - beatSnapGrid.SelectionTimeRange = null; - } - } - public override Playfield Playfield => drawableRulesetWrapper.Playfield; public override IEnumerable HitObjects => drawableRulesetWrapper.Playfield.AllHitObjects; @@ -336,12 +300,6 @@ namespace osu.Game.Rulesets.Edit /// protected virtual ComposeBlueprintContainer CreateBlueprintContainer() => new ComposeBlueprintContainer(this); - /// - /// Construct an optional beat snap grid. - /// - [CanBeNull] - protected virtual BeatSnapGrid CreateBeatSnapGrid() => null; - /// /// Construct a drawable ruleset for the provided ruleset. /// diff --git a/osu.Game/Rulesets/Edit/ScrollingHitObjectComposer.cs b/osu.Game/Rulesets/Edit/ScrollingHitObjectComposer.cs index cb92ebbd15..eb73cef01a 100644 --- a/osu.Game/Rulesets/Edit/ScrollingHitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/ScrollingHitObjectComposer.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.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -8,9 +9,11 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Game.Configuration; using osu.Game.Graphics.UserInterface; +using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Screens.Edit.Components.TernaryButtons; +using osu.Game.Screens.Edit.Compose.Components; using osuTK; namespace osu.Game.Rulesets.Edit @@ -21,6 +24,13 @@ namespace osu.Game.Rulesets.Edit private readonly Bindable showSpeedChanges = new Bindable(); private Bindable configShowSpeedChanges = null!; + private BeatSnapGrid? beatSnapGrid; + + /// + /// Construct an optional beat snap grid. + /// + protected virtual BeatSnapGrid? CreateBeatSnapGrid() => null; + protected ScrollingHitObjectComposer(Ruleset ruleset) : base(ruleset) { @@ -57,6 +67,42 @@ namespace osu.Game.Rulesets.Edit configShowSpeedChanges.Value = enabled; }, true); } + + beatSnapGrid = CreateBeatSnapGrid(); + + if (beatSnapGrid != null) + AddInternal(beatSnapGrid); + } + + protected override void UpdateAfterChildren() + { + base.UpdateAfterChildren(); + + updateBeatSnapGrid(); + } + + private void updateBeatSnapGrid() + { + if (beatSnapGrid == null) + return; + + if (BlueprintContainer.CurrentTool is SelectTool) + { + if (EditorBeatmap.SelectedHitObjects.Any()) + { + beatSnapGrid.SelectionTimeRange = (EditorBeatmap.SelectedHitObjects.Min(h => h.StartTime), EditorBeatmap.SelectedHitObjects.Max(h => h.GetEndTime())); + } + else + beatSnapGrid.SelectionTimeRange = null; + } + else + { + var result = FindSnappedPositionAndTime(InputManager.CurrentState.Mouse.Position); + if (result.Time is double time) + beatSnapGrid.SelectionTimeRange = (time, time); + else + beatSnapGrid.SelectionTimeRange = null; + } } } } From 74b86349d58e5169e52bbdc70cef3dec81579a74 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Oct 2023 23:57:36 +0900 Subject: [PATCH 09/10] Tidy up `CatchHitObjectComposer` --- .../Edit/CatchHitObjectComposer.cs | 56 ++++++------------- 1 file changed, 17 insertions(+), 39 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs index 9b258841b2..6f0ee260ab 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs @@ -10,7 +10,6 @@ using osu.Framework.Graphics; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Game.Beatmaps; -using osu.Game.Graphics.UserInterface; using osu.Game.Input.Bindings; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.UI; @@ -75,6 +74,23 @@ namespace osu.Game.Rulesets.Catch.Edit => base.CreateTernaryButtons() .Concat(DistanceSnapProvider.CreateTernaryButtons()); + protected override DrawableRuleset CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList mods) => + new DrawableCatchEditorRuleset(ruleset, beatmap, mods) + { + TimeRangeMultiplier = { BindTarget = timeRangeMultiplier, } + }; + + protected override ComposeBlueprintContainer CreateBlueprintContainer() => new CatchBlueprintContainer(this); + + protected override BeatSnapGrid CreateBeatSnapGrid() => new CatchBeatSnapGrid(); + + protected override IReadOnlyList CompositionTools => new HitObjectCompositionTool[] + { + new FruitCompositionTool(), + new JuiceStreamCompositionTool(), + new BananaShowerCompositionTool() + }; + public bool OnPressed(KeyBindingPressEvent e) { switch (e.Action) @@ -98,19 +114,6 @@ namespace osu.Game.Rulesets.Catch.Edit { } - protected override DrawableRuleset CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList mods) => - new DrawableCatchEditorRuleset(ruleset, beatmap, mods) - { - TimeRangeMultiplier = { BindTarget = timeRangeMultiplier, } - }; - - protected override IReadOnlyList CompositionTools => new HitObjectCompositionTool[] - { - new FruitCompositionTool(), - new JuiceStreamCompositionTool(), - new BananaShowerCompositionTool() - }; - public override SnapResult FindSnappedPositionAndTime(Vector2 screenSpacePosition, SnapType snapType = SnapType.All) { var result = base.FindSnappedPositionAndTime(screenSpacePosition, snapType); @@ -129,10 +132,6 @@ namespace osu.Game.Rulesets.Catch.Edit return result; } - protected override ComposeBlueprintContainer CreateBlueprintContainer() => new CatchBlueprintContainer(this); - - protected override BeatSnapGrid CreateBeatSnapGrid() => new CatchBeatSnapGrid(); - private PalpableCatchHitObject? getLastSnappableHitObject(double time) { var hitObject = EditorBeatmap.HitObjects.OfType().LastOrDefault(h => h.GetEndTime() < time && !(h is BananaShower)); @@ -180,26 +179,5 @@ namespace osu.Game.Rulesets.Catch.Edit return null; } } - - private void updateDistanceSnapGrid() - { - if (DistanceSnapProvider.DistanceSnapToggle.Value != TernaryState.True) - { - distanceSnapGrid.Hide(); - return; - } - - var sourceHitObject = getDistanceSnapGridSourceHitObject(); - - if (sourceHitObject == null) - { - distanceSnapGrid.Hide(); - return; - } - - distanceSnapGrid.Show(); - distanceSnapGrid.StartTime = sourceHitObject.GetEndTime(); - distanceSnapGrid.StartX = sourceHitObject.EffectiveX; - } } } From 2c6bf9e3469e4c004a41508dd802cad9b3882c61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 19 Oct 2023 20:45:47 +0200 Subject: [PATCH 10/10] Remove unused using directive --- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index b68af49222..07e5869e28 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -7,7 +7,6 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.EnumExtensions;