From 70931abcb0a2b80cfc9aaecbddbc71e6c7ff5b89 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 1 Oct 2020 17:54:54 +0900 Subject: [PATCH 1/8] Separate out timeline control point display from summary timeline display --- .../Timeline/DifficultyPointPiece.cs | 66 +++++++++++++++++++ .../Compose/Components/Timeline/Timeline.cs | 10 ++- .../Timeline/TimelineControlPointDisplay.cs | 57 ++++++++++++++++ .../Timeline/TimelineControlPointGroup.cs | 55 ++++++++++++++++ 4 files changed, 182 insertions(+), 6 deletions(-) create mode 100644 osu.Game/Screens/Edit/Compose/Components/Timeline/DifficultyPointPiece.cs create mode 100644 osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointDisplay.cs create mode 100644 osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointGroup.cs diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/DifficultyPointPiece.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/DifficultyPointPiece.cs new file mode 100644 index 0000000000..4d5970d7e7 --- /dev/null +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/DifficultyPointPiece.cs @@ -0,0 +1,66 @@ +// 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.Shapes; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osuTK.Graphics; + +namespace osu.Game.Screens.Edit.Compose.Components.Timeline +{ + public class DifficultyPointPiece : CompositeDrawable + { + private OsuSpriteText speedMultiplierText; + private readonly BindableNumber speedMultiplier; + + public DifficultyPointPiece(DifficultyControlPoint point) + { + speedMultiplier = point.SpeedMultiplierBindable.GetBoundCopy(); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + RelativeSizeAxes = Axes.Y; + AutoSizeAxes = Axes.X; + + Color4 colour = colours.GreenDark; + + InternalChildren = new Drawable[] + { + new Box + { + Colour = colour, + Width = 2, + RelativeSizeAxes = Axes.Y, + }, + new Container + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + AutoSizeAxes = Axes.Both, + Children = new Drawable[] + { + new Box + { + Colour = colour, + RelativeSizeAxes = Axes.Both, + }, + speedMultiplierText = new OsuSpriteText + { + Font = OsuFont.Default.With(weight: FontWeight.Bold), + Colour = Color4.White, + } + } + }, + }; + + speedMultiplier.BindValueChanged(multiplier => speedMultiplierText.Text = $"{multiplier.NewValue:n2}x", true); + } + } +} diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs index 3e54813a14..3d2e2ebef7 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs @@ -13,7 +13,6 @@ using osu.Framework.Input.Events; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Rulesets.Edit; -using osu.Game.Screens.Edit.Components.Timelines.Summary.Parts; using osuTK; namespace osu.Game.Screens.Edit.Compose.Components.Timeline @@ -63,9 +62,11 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline } private WaveformGraph waveform; - private ControlPointPart controlPoints; + private TimelineTickDisplay ticks; + private TimelineControlPointDisplay controlPoints; + [BackgroundDependencyLoader] private void load(IBindable beatmap, OsuColour colours) { @@ -85,10 +86,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline MidColour = colours.BlueDark, HighColour = colours.BlueDarker, }, - controlPoints = new ControlPointPart - { - RelativeSizeAxes = Axes.Both - }, + controlPoints = new TimelineControlPointDisplay(), ticks = new TimelineTickDisplay(), } }, diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointDisplay.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointDisplay.cs new file mode 100644 index 0000000000..3f13e8e5d4 --- /dev/null +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointDisplay.cs @@ -0,0 +1,57 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Specialized; +using System.Linq; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Screens.Edit.Components.Timelines.Summary.Parts; + +namespace osu.Game.Screens.Edit.Compose.Components.Timeline +{ + /// + /// The part of the timeline that displays the control points. + /// + public class TimelineControlPointDisplay : TimelinePart + { + private IBindableList controlPointGroups; + + public TimelineControlPointDisplay() + { + RelativeSizeAxes = Axes.Both; + } + + protected override void LoadBeatmap(WorkingBeatmap beatmap) + { + base.LoadBeatmap(beatmap); + + controlPointGroups = beatmap.Beatmap.ControlPointInfo.Groups.GetBoundCopy(); + controlPointGroups.BindCollectionChanged((sender, args) => + { + switch (args.Action) + { + case NotifyCollectionChangedAction.Reset: + Clear(); + break; + + case NotifyCollectionChangedAction.Add: + foreach (var group in args.NewItems.OfType()) + Add(new TimelineControlPointGroup(group)); + break; + + case NotifyCollectionChangedAction.Remove: + foreach (var group in args.OldItems.OfType()) + { + var matching = Children.SingleOrDefault(gv => gv.Group == group); + + matching?.Expire(); + } + + break; + } + }, true); + } + } +} diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointGroup.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointGroup.cs new file mode 100644 index 0000000000..5429e7c55b --- /dev/null +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointGroup.cs @@ -0,0 +1,55 @@ +// 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.Game.Beatmaps.ControlPoints; +using osu.Game.Graphics; + +namespace osu.Game.Screens.Edit.Compose.Components.Timeline +{ + public class TimelineControlPointGroup : CompositeDrawable + { + public readonly ControlPointGroup Group; + + private BindableList controlPoints; + + [Resolved] + private OsuColour colours { get; set; } + + public TimelineControlPointGroup(ControlPointGroup group) + { + Origin = Anchor.TopCentre; + + Group = group; + + RelativePositionAxes = Axes.X; + RelativeSizeAxes = Axes.Y; + + Width = 1; + + X = (float)group.Time; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + controlPoints = (BindableList)Group.ControlPoints.GetBoundCopy(); + controlPoints.BindCollectionChanged((_, __) => + { + foreach (var point in controlPoints) + { + switch (point) + { + case DifficultyControlPoint difficultyPoint: + AddInternal(new DifficultyPointPiece(difficultyPoint)); + break; + } + } + }, true); + } + } +} From 0bced34272de9f403bd85c47a5d99ffb844870e3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 1 Oct 2020 18:07:39 +0900 Subject: [PATCH 2/8] Add visualisation of bpm (timing) changes to timeline --- .../Timeline/TimelineControlPointGroup.cs | 11 ++-- .../Components/Timeline/TimingPointPiece.cs | 57 +++++++++++++++++++ 2 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 osu.Game/Screens/Edit/Compose/Components/Timeline/TimingPointPiece.cs diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointGroup.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointGroup.cs index 5429e7c55b..05a7f6e493 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointGroup.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointGroup.cs @@ -21,14 +21,11 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline public TimelineControlPointGroup(ControlPointGroup group) { - Origin = Anchor.TopCentre; - Group = group; RelativePositionAxes = Axes.X; RelativeSizeAxes = Axes.Y; - - Width = 1; + AutoSizeAxes = Axes.X; X = (float)group.Time; } @@ -40,6 +37,8 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline controlPoints = (BindableList)Group.ControlPoints.GetBoundCopy(); controlPoints.BindCollectionChanged((_, __) => { + ClearInternal(); + foreach (var point in controlPoints) { switch (point) @@ -47,6 +46,10 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline case DifficultyControlPoint difficultyPoint: AddInternal(new DifficultyPointPiece(difficultyPoint)); break; + + case TimingControlPoint timingPoint: + AddInternal(new TimingPointPiece(timingPoint)); + break; } } }, true); diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimingPointPiece.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimingPointPiece.cs new file mode 100644 index 0000000000..de7cfecbf0 --- /dev/null +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimingPointPiece.cs @@ -0,0 +1,57 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; + +namespace osu.Game.Screens.Edit.Compose.Components.Timeline +{ + public class TimingPointPiece : CompositeDrawable + { + private readonly BindableNumber beatLength; + private OsuSpriteText bpmText; + + public TimingPointPiece(TimingControlPoint point) + { + beatLength = point.BeatLengthBindable.GetBoundCopy(); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + Origin = Anchor.CentreLeft; + Anchor = Anchor.CentreLeft; + + AutoSizeAxes = Axes.Both; + + InternalChildren = new Drawable[] + { + new Box + { + Alpha = 0.9f, + Colour = ColourInfo.GradientHorizontal(colours.YellowDark, colours.YellowDark.Opacity(0.5f)), + RelativeSizeAxes = Axes.Both, + }, + bpmText = new OsuSpriteText + { + Alpha = 0.9f, + Padding = new MarginPadding(3), + Font = OsuFont.Default.With(size: 40) + } + }; + + beatLength.BindValueChanged(beatLength => + { + bpmText.Text = $"{60000 / beatLength.NewValue:n1} BPM"; + }, true); + } + } +} From b75c202a7e5547b4cf4d12c15bc1537418150ab8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 1 Oct 2020 18:49:48 +0900 Subject: [PATCH 3/8] Add sample control point display in timeline --- .../Timeline/DifficultyPointPiece.cs | 2 - .../Components/Timeline/SamplePointPiece.cs | 81 +++++++++++++++++++ .../Timeline/TimelineControlPointGroup.cs | 4 + 3 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/DifficultyPointPiece.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/DifficultyPointPiece.cs index 4d5970d7e7..31cc768056 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/DifficultyPointPiece.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/DifficultyPointPiece.cs @@ -41,8 +41,6 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline }, new Container { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, AutoSizeAxes = Axes.Both, Children = new Drawable[] { diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs new file mode 100644 index 0000000000..67da335f6b --- /dev/null +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs @@ -0,0 +1,81 @@ +// 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.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osuTK.Graphics; + +namespace osu.Game.Screens.Edit.Compose.Components.Timeline +{ + public class SamplePointPiece : CompositeDrawable + { + private readonly Bindable bank; + private readonly BindableNumber volume; + + private OsuSpriteText text; + private Box volumeBox; + + public SamplePointPiece(SampleControlPoint samplePoint) + { + volume = samplePoint.SampleVolumeBindable.GetBoundCopy(); + bank = samplePoint.SampleBankBindable.GetBoundCopy(); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + Origin = Anchor.TopLeft; + Anchor = Anchor.TopLeft; + + AutoSizeAxes = Axes.X; + RelativeSizeAxes = Axes.Y; + + Color4 colour = colours.BlueDarker; + + InternalChildren = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Y, + Width = 20, + Children = new Drawable[] + { + volumeBox = new Box + { + X = 2, + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Colour = ColourInfo.GradientVertical(colour, Color4.Black), + RelativeSizeAxes = Axes.Both, + }, + new Box + { + Colour = colours.Blue, + Width = 2, + RelativeSizeAxes = Axes.Y, + }, + } + }, + text = new OsuSpriteText + { + X = 2, + Y = -5, + Anchor = Anchor.BottomLeft, + Alpha = 0.9f, + Rotation = -90, + Font = OsuFont.Default.With(weight: FontWeight.SemiBold) + } + }; + + volume.BindValueChanged(volume => volumeBox.Height = volume.NewValue / 100f, true); + bank.BindValueChanged(bank => text.Text = $"{bank.NewValue}", true); + } + } +} diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointGroup.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointGroup.cs index 05a7f6e493..1a09a05a6c 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointGroup.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointGroup.cs @@ -50,6 +50,10 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline case TimingControlPoint timingPoint: AddInternal(new TimingPointPiece(timingPoint)); break; + + case SampleControlPoint samplePoint: + AddInternal(new SamplePointPiece(samplePoint)); + break; } } }, true); From 589a26a149d11b99c70560b117d79913729d4f59 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 1 Oct 2020 18:59:35 +0900 Subject: [PATCH 4/8] Ensure stable display order for control points in the same group --- .../Compose/Components/Timeline/TimelineControlPointGroup.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointGroup.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointGroup.cs index 1a09a05a6c..e32616a574 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointGroup.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointGroup.cs @@ -44,7 +44,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline switch (point) { case DifficultyControlPoint difficultyPoint: - AddInternal(new DifficultyPointPiece(difficultyPoint)); + AddInternal(new DifficultyPointPiece(difficultyPoint) { Depth = -2 }); break; case TimingControlPoint timingPoint: @@ -52,7 +52,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline break; case SampleControlPoint samplePoint: - AddInternal(new SamplePointPiece(samplePoint)); + AddInternal(new SamplePointPiece(samplePoint) { Depth = -1 }); break; } } From fcccce8b4e2f5466059906b82c4ad1f76ba45df7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 1 Oct 2020 19:03:17 +0900 Subject: [PATCH 5/8] Use pink for sample control points to avoid clash with waveform blue --- .../Edit/Compose/Components/Timeline/SamplePointPiece.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs index 67da335f6b..6a6e947343 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs @@ -37,7 +37,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline AutoSizeAxes = Axes.X; RelativeSizeAxes = Axes.Y; - Color4 colour = colours.BlueDarker; + Color4 colour = colours.PinkDarker; InternalChildren = new Drawable[] { @@ -57,7 +57,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline }, new Box { - Colour = colours.Blue, + Colour = colours.Pink, Width = 2, RelativeSizeAxes = Axes.Y, }, From 5ad2944e26e9714a10006ad2879a0840623b46d5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 1 Oct 2020 19:31:41 +0900 Subject: [PATCH 6/8] Fix ticks displaying higher than control point info --- osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs index 3d2e2ebef7..be3bca3242 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs @@ -86,8 +86,8 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline MidColour = colours.BlueDark, HighColour = colours.BlueDarker, }, - controlPoints = new TimelineControlPointDisplay(), ticks = new TimelineTickDisplay(), + controlPoints = new TimelineControlPointDisplay(), } }, }); From 0d3a95d8fca626aededdff8bbc4e329b4401818c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Oct 2020 19:54:13 +0900 Subject: [PATCH 7/8] Remove unnecessary string interpolation --- .../Edit/Compose/Components/Timeline/SamplePointPiece.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs index 6a6e947343..37c8c8402a 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs @@ -75,7 +75,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline }; volume.BindValueChanged(volume => volumeBox.Height = volume.NewValue / 100f, true); - bank.BindValueChanged(bank => text.Text = $"{bank.NewValue}", true); + bank.BindValueChanged(bank => text.Text = bank.NewValue, true); } } } From 6bc0afdafb32c9e5728458fa8e099b39e9f7902a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 5 Oct 2020 20:09:18 +0900 Subject: [PATCH 8/8] Fix remaining conflicts --- osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs index 0bb3d25011..be3bca3242 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs @@ -13,7 +13,6 @@ using osu.Framework.Input.Events; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Rulesets.Edit; -using osu.Game.Screens.Edit.Components.Timelines.Summary.Parts; using osuTK; namespace osu.Game.Screens.Edit.Compose.Components.Timeline @@ -63,8 +62,6 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline } private WaveformGraph waveform; - private ControlPointPart controlPoints; - private TimelineTickDisplay ticks; private TimelineTickDisplay ticks;