From f9568619e7a71655192b56556b4a30f8c93f2dc7 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Wed, 20 Sep 2017 16:59:03 +0900 Subject: [PATCH] Move SummaryTimeline into /Edit/Components/SummaryTimeline --- .../Edit/Components/SummaryTimeline.cs | 356 ++++++++++++++++++ .../Visual/TestCaseEditorSummaryTimeline.cs | 340 +---------------- osu.Game/osu.Game.csproj | 1 + 3 files changed, 361 insertions(+), 336 deletions(-) create mode 100644 osu.Game/Screens/Edit/Components/SummaryTimeline.cs diff --git a/osu.Game/Screens/Edit/Components/SummaryTimeline.cs b/osu.Game/Screens/Edit/Components/SummaryTimeline.cs new file mode 100644 index 0000000000..ffb54ba7b1 --- /dev/null +++ b/osu.Game/Screens/Edit/Components/SummaryTimeline.cs @@ -0,0 +1,356 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Linq; +using OpenTK; +using osu.Framework.Allocation; +using osu.Framework.Configuration; +using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Beatmaps.Timing; +using osu.Game.Graphics; + +namespace osu.Game.Screens.Edit.Components +{ + /// + /// The timeline that sits at the bottom of the editor. + /// + public class SummaryTimeline : CompositeDrawable + { + private const float corner_radius = 5; + private const float contents_padding = 15; + private const float marker_bar_width = 2; + + private readonly Drawable background; + + private readonly Container markerContainer; + + private readonly Drawable timelineBar; + private readonly Drawable marker; + + private readonly Bindable beatmap = new Bindable(); + + public SummaryTimeline() + { + Masking = true; + CornerRadius = 5; + + InternalChildren = new[] + { + background = new Box { RelativeSizeAxes = Axes.Both }, + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Left = contents_padding, Right = contents_padding }, + Children = new[] + { + markerContainer = new Container + { + RelativeSizeAxes = Axes.Both, + Child = marker = new Container + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.Centre, + RelativePositionAxes = Axes.X, + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Children = new Drawable[] + { + new Triangle + { + Anchor = Anchor.TopCentre, + Origin = Anchor.BottomCentre, + Scale = new Vector2(1, -1), + Size = new Vector2(10, 5), + }, + new Triangle + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Size = new Vector2(10, 5) + }, + new Box + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Y, + Width = 2, + EdgeSmoothness = new Vector2(1, 0) + } + } + } + }, + new ControlPointTimeline + { + Anchor = Anchor.Centre, + Origin = Anchor.BottomCentre, + RelativeSizeAxes = Axes.Both, + Height = 0.35f + }, + new BookmarkTimeline + { + Anchor = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Height = 0.35f + }, + timelineBar = new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + new Circle + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreRight, + Size = new Vector2(5) + }, + new Box + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + RelativeSizeAxes = Axes.X, + Height = 1, + EdgeSmoothness = new Vector2(0, 1), + }, + new Circle + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreLeft, + Size = new Vector2(5) + }, + } + }, + new BreakTimeline + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Height = 0.25f + } + } + } + }; + } + + [BackgroundDependencyLoader] + private void load(OsuGameBase osuGame, OsuColour colours) + { + background.Colour = colours.Gray1; + marker.Colour = colours.Red; + timelineBar.Colour = colours.Gray5; + + beatmap.BindTo(osuGame.Beatmap); + + markerContainer.RelativeChildSize = new Vector2((float)Math.Max(1, beatmap.Value.Track.Length), 1); + beatmap.ValueChanged += b => markerContainer.RelativeChildSize = new Vector2((float)Math.Max(1, b.Track.Length), 1); + } + + protected override bool OnDragStart(InputState state) => true; + protected override bool OnDragEnd(InputState state) => true; + protected override bool OnDrag(InputState state) + { + seekToPosition(state.Mouse.NativeState.Position); + return true; + } + + protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) + { + seekToPosition(state.Mouse.NativeState.Position); + return true; + } + + /// + /// Seeks the to the time closest to a position on the screen relative to the . + /// + /// The position in screen coordinates. + private void seekToPosition(Vector2 screenPosition) + { + float markerPos = MathHelper.Clamp(markerContainer.ToLocalSpace(screenPosition).X, 0, markerContainer.DrawWidth); + seekTo(markerPos / markerContainer.DrawWidth * beatmap.Value.Track.Length); + } + + private void seekTo(double time) => beatmap.Value.Track.Seek(time); + + protected override void Update() + { + base.Update(); + marker.X = (float)beatmap.Value.Track.CurrentTime; + } + + /// + /// The part of the timeline that displays the control points. + /// + private class ControlPointTimeline : Timeline + { + protected override void LoadBeatmap(WorkingBeatmap beatmap) + { + ControlPointInfo cpi = beatmap.Beatmap.ControlPointInfo; + + cpi.TimingPoints.ForEach(addTimingPoint); + + // Consider all non-timing points as the same type + cpi.SoundPoints.Select(c => (ControlPoint)c) + .Concat(cpi.EffectPoints) + .Concat(cpi.DifficultyPoints) + .Distinct() + // Non-timing points should not be added where there are timing points + .Where(c => cpi.TimingPointAt(c.Time).Time != c.Time) + .ForEach(addNonTimingPoint); + } + + private void addTimingPoint(ControlPoint controlPoint) => Add(new TimingPointVisualisation(controlPoint)); + private void addNonTimingPoint(ControlPoint controlPoint) => Add(new NonTimingPointVisualisation(controlPoint)); + + private class TimingPointVisualisation : ControlPointVisualisation + { + public TimingPointVisualisation(ControlPoint controlPoint) + : base(controlPoint) + { + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) => Colour = colours.YellowDark; + } + + private class NonTimingPointVisualisation : ControlPointVisualisation + { + public NonTimingPointVisualisation(ControlPoint controlPoint) + : base(controlPoint) + { + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) => Colour = colours.Green; + } + + private abstract class ControlPointVisualisation : PointVisualisation + { + protected ControlPointVisualisation(ControlPoint controlPoint) + : base(controlPoint.Time) + { + } + } + } + + /// + /// The part of the timeline that displays bookmarks. + /// + private class BookmarkTimeline : Timeline + { + protected override void LoadBeatmap(WorkingBeatmap beatmap) + { + foreach (int bookmark in beatmap.BeatmapInfo.Bookmarks) + Add(new BookmarkVisualisation(bookmark)); + } + + private class BookmarkVisualisation : PointVisualisation + { + public BookmarkVisualisation(double startTime) + : base(startTime) + { + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) => Colour = colours.Blue; + } + } + + /// + /// The part of the timeline that displays breaks in the song. + /// + private class BreakTimeline : Timeline + { + protected override void LoadBeatmap(WorkingBeatmap beatmap) + { + foreach (var breakPeriod in beatmap.Beatmap.Breaks) + Add(new BreakVisualisation(breakPeriod)); + } + + private class BreakVisualisation : DurationVisualisation + { + public BreakVisualisation(BreakPeriod breakPeriod) + : base(breakPeriod.StartTime, breakPeriod.EndTime) + { + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) => Colour = colours.Yellow; + } + } + + /// + /// Represents a part of the editor timeline. + /// + private abstract class Timeline : CompositeDrawable + { + private readonly Container timeline; + + protected Timeline() + { + AddInternal(timeline = new Container { RelativeSizeAxes = Axes.Both }); + } + + [BackgroundDependencyLoader] + private void load(OsuGameBase osuGame) + { + osuGame.Beatmap.ValueChanged += b => + { + timeline.Clear(); + timeline.RelativeChildSize = new Vector2((float)Math.Max(1, b.Track.Length), 1); + LoadBeatmap(b); + }; + + timeline.RelativeChildSize = new Vector2((float)Math.Max(1, osuGame.Beatmap.Value.Track.Length), 1); + LoadBeatmap(osuGame.Beatmap); + } + + protected void Add(PointVisualisation visualisation) => timeline.Add(visualisation); + protected void Add(DurationVisualisation visualisation) => timeline.Add(visualisation); + + protected abstract void LoadBeatmap(WorkingBeatmap beatmap); + } + + /// + /// Represents a singular point on a . + /// + private class PointVisualisation : Box + { + protected PointVisualisation(double startTime) + { + Origin = Anchor.TopCentre; + + RelativeSizeAxes = Axes.Y; + Width = 1; + EdgeSmoothness = new Vector2(1, 0); + + RelativePositionAxes = Axes.X; + X = (float)startTime; + } + } + + /// + /// Represents a spanning point on a . + /// + private class DurationVisualisation : Container + { + protected DurationVisualisation(double startTime, double endTime) + { + Masking = true; + CornerRadius = corner_radius; + + RelativePositionAxes = Axes.X; + RelativeSizeAxes = Axes.Both; + X = (float)startTime; + Width = (float)(endTime - startTime); + + AddInternal(new Box { RelativeSizeAxes = Axes.Both }); + } + } + } +} diff --git a/osu.Game/Tests/Visual/TestCaseEditorSummaryTimeline.cs b/osu.Game/Tests/Visual/TestCaseEditorSummaryTimeline.cs index 9c9c7e963b..ee7f54f771 100644 --- a/osu.Game/Tests/Visual/TestCaseEditorSummaryTimeline.cs +++ b/osu.Game/Tests/Visual/TestCaseEditorSummaryTimeline.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.Collections.Generic; using System.Linq; using OpenTK; using osu.Framework.Allocation; @@ -17,6 +18,7 @@ using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.Timing; using osu.Game.Graphics; +using osu.Game.Screens.Edit.Components; namespace osu.Game.Tests.Visual { @@ -25,6 +27,8 @@ namespace osu.Game.Tests.Visual private const int length = 60000; private readonly Random random; + public override IReadOnlyList RequiredTypes => new Type[] { typeof(SummaryTimeline) }; + public TestCaseEditorSummaryTimeline() { random = new Random(1337); @@ -85,341 +89,5 @@ namespace osu.Game.Tests.Visual } } } - - /// - /// The timeline that sits at the bottom of the editor. - /// - private class SummaryTimeline : CompositeDrawable - { - private const float corner_radius = 5; - private const float contents_padding = 15; - private const float marker_bar_width = 2; - - private readonly Drawable background; - - private readonly Container markerContainer; - - private readonly Drawable timelineBar; - private readonly Drawable marker; - - private readonly Bindable beatmap = new Bindable(); - - public SummaryTimeline() - { - Masking = true; - CornerRadius = 5; - - InternalChildren = new[] - { - background = new Box { RelativeSizeAxes = Axes.Both }, - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Left = contents_padding, Right = contents_padding }, - Children = new[] - { - markerContainer = new Container - { - RelativeSizeAxes = Axes.Both, - Child = marker = new Container - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.Centre, - RelativePositionAxes = Axes.X, - RelativeSizeAxes = Axes.Y, - AutoSizeAxes = Axes.X, - Children = new Drawable[] - { - new Triangle - { - Anchor = Anchor.TopCentre, - Origin = Anchor.BottomCentre, - Scale = new Vector2(1, -1), - Size = new Vector2(10, 5), - }, - new Triangle - { - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - Size = new Vector2(10, 5) - }, - new Box - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Y, - Width = 2, - EdgeSmoothness = new Vector2(1, 0) - } - } - } - }, - new ControlPointTimeline - { - Anchor = Anchor.Centre, - Origin = Anchor.BottomCentre, - RelativeSizeAxes = Axes.Both, - Height = 0.35f - }, - new BookmarkTimeline - { - Anchor = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Height = 0.35f - }, - timelineBar = new Container - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - new Circle - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreRight, - Size = new Vector2(5) - }, - new Box - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - RelativeSizeAxes = Axes.X, - Height = 1, - EdgeSmoothness = new Vector2(0, 1), - }, - new Circle - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreLeft, - Size = new Vector2(5) - }, - } - }, - new BreakTimeline - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Height = 0.25f - } - } - } - }; - } - - [BackgroundDependencyLoader] - private void load(OsuGameBase osuGame, OsuColour colours) - { - background.Colour = colours.Gray1; - marker.Colour = colours.Red; - timelineBar.Colour = colours.Gray5; - - beatmap.BindTo(osuGame.Beatmap); - - markerContainer.RelativeChildSize = new Vector2((float)Math.Max(1, beatmap.Value.Track.Length), 1); - beatmap.ValueChanged += b => markerContainer.RelativeChildSize = new Vector2((float)Math.Max(1, b.Track.Length), 1); - } - - protected override bool OnDragStart(InputState state) => true; - protected override bool OnDragEnd(InputState state) => true; - protected override bool OnDrag(InputState state) - { - seekToPosition(state.Mouse.NativeState.Position); - return true; - } - - protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) - { - seekToPosition(state.Mouse.NativeState.Position); - return true; - } - - /// - /// Seeks the to the time closest to a position on the screen relative to the . - /// - /// The position in screen coordinates. - private void seekToPosition(Vector2 screenPosition) - { - float markerPos = MathHelper.Clamp(markerContainer.ToLocalSpace(screenPosition).X, 0, markerContainer.DrawWidth); - seekTo(markerPos / markerContainer.DrawWidth * beatmap.Value.Track.Length); - } - - private void seekTo(double time) => beatmap.Value.Track.Seek(time); - - protected override void Update() - { - base.Update(); - marker.X = (float)beatmap.Value.Track.CurrentTime; - } - - /// - /// The part of the timeline that displays the control points. - /// - private class ControlPointTimeline : Timeline - { - protected override void LoadBeatmap(WorkingBeatmap beatmap) - { - ControlPointInfo cpi = beatmap.Beatmap.ControlPointInfo; - - cpi.TimingPoints.ForEach(addTimingPoint); - - // Consider all non-timing points as the same type - cpi.SoundPoints.Select(c => (ControlPoint)c) - .Concat(cpi.EffectPoints) - .Concat(cpi.DifficultyPoints) - .Distinct() - // Non-timing points should not be added where there are timing points - .Where(c => cpi.TimingPointAt(c.Time).Time != c.Time) - .ForEach(addNonTimingPoint); - } - - private void addTimingPoint(ControlPoint controlPoint) => Add(new TimingPointVisualisation(controlPoint)); - private void addNonTimingPoint(ControlPoint controlPoint) => Add(new NonTimingPointVisualisation(controlPoint)); - - private class TimingPointVisualisation : ControlPointVisualisation - { - public TimingPointVisualisation(ControlPoint controlPoint) - : base(controlPoint) - { - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) => Colour = colours.YellowDark; - } - - private class NonTimingPointVisualisation : ControlPointVisualisation - { - public NonTimingPointVisualisation(ControlPoint controlPoint) - : base(controlPoint) - { - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) => Colour = colours.Green; - } - - private abstract class ControlPointVisualisation : PointVisualisation - { - protected ControlPointVisualisation(ControlPoint controlPoint) - : base(controlPoint.Time) - { - } - } - } - - /// - /// The part of the timeline that displays bookmarks. - /// - private class BookmarkTimeline : Timeline - { - protected override void LoadBeatmap(WorkingBeatmap beatmap) - { - foreach (int bookmark in beatmap.BeatmapInfo.Bookmarks) - Add(new BookmarkVisualisation(bookmark)); - } - - private class BookmarkVisualisation : PointVisualisation - { - public BookmarkVisualisation(double startTime) - : base(startTime) - { - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) => Colour = colours.Blue; - } - } - - /// - /// The part of the timeline that displays breaks in the song. - /// - private class BreakTimeline : Timeline - { - protected override void LoadBeatmap(WorkingBeatmap beatmap) - { - foreach (var breakPeriod in beatmap.Beatmap.Breaks) - Add(new BreakVisualisation(breakPeriod)); - } - - private class BreakVisualisation : DurationVisualisation - { - public BreakVisualisation(BreakPeriod breakPeriod) - : base(breakPeriod.StartTime, breakPeriod.EndTime) - { - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) => Colour = colours.Yellow; - } - } - - /// - /// Represents a part of the editor timeline. - /// - private abstract class Timeline : CompositeDrawable - { - private readonly Container timeline; - - protected Timeline() - { - AddInternal(timeline = new Container { RelativeSizeAxes = Axes.Both }); - } - - [BackgroundDependencyLoader] - private void load(OsuGameBase osuGame) - { - osuGame.Beatmap.ValueChanged += b => - { - timeline.Clear(); - timeline.RelativeChildSize = new Vector2((float)Math.Max(1, b.Track.Length), 1); - LoadBeatmap(b); - }; - - timeline.RelativeChildSize = new Vector2((float)Math.Max(1, osuGame.Beatmap.Value.Track.Length), 1); - LoadBeatmap(osuGame.Beatmap); - } - - protected void Add(PointVisualisation visualisation) => timeline.Add(visualisation); - protected void Add(DurationVisualisation visualisation) => timeline.Add(visualisation); - - protected abstract void LoadBeatmap(WorkingBeatmap beatmap); - } - - /// - /// Represents a singular point on a . - /// - private class PointVisualisation : Box - { - protected PointVisualisation(double startTime) - { - Origin = Anchor.TopCentre; - - RelativeSizeAxes = Axes.Y; - Width = 1; - EdgeSmoothness = new Vector2(1, 0); - - RelativePositionAxes = Axes.X; - X = (float)startTime; - } - } - - /// - /// Represents a spanning point on a . - /// - private class DurationVisualisation : Container - { - protected DurationVisualisation(double startTime, double endTime) - { - Masking = true; - CornerRadius = corner_radius; - - RelativePositionAxes = Axes.X; - RelativeSizeAxes = Axes.Both; - X = (float)startTime; - Width = (float)(endTime - startTime); - - AddInternal(new Box { RelativeSizeAxes = Axes.Both }); - } - } - } } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index fde6133aac..768d46dce4 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -604,6 +604,7 @@ +