From b020fe0d50c82a2eb2d38ff716c4546e90532417 Mon Sep 17 00:00:00 2001
From: EVAST9919 <megaman9919@gmail.com>
Date: Fri, 23 Jun 2017 08:36:47 +0300
Subject: [PATCH 01/41] Added TestCase

---
 .../Tests/TestCaseBeatSyncedContainer.cs      | 186 ++++++++++++++++++
 1 file changed, 186 insertions(+)
 create mode 100644 osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs

diff --git a/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs b/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
new file mode 100644
index 0000000000..a8fa8bf218
--- /dev/null
+++ b/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
@@ -0,0 +1,186 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.Testing;
+using osu.Framework.Graphics;
+using osu.Framework.Timing;
+using osu.Game.Overlays;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Graphics.Containers;
+using osu.Framework.Audio.Track;
+using osu.Game.Beatmaps.ControlPoints;
+using osu.Framework.Graphics.Shapes;
+using OpenTK.Graphics;
+using osu.Game.Graphics.Sprites;
+using osu.Framework.Lists;
+using System;
+using System.Globalization;
+
+namespace osu.Desktop.VisualTests.Tests
+{
+    internal class TestCaseBeatSyncedContainer : TestCase
+    {
+        public override string Description => @"Tests beat synced containers.";
+
+        private MusicController mc;
+
+        public TestCaseBeatSyncedContainer()
+        {
+            Clock = new FramedClock();
+        }
+
+        public override void Reset()
+        {
+            base.Reset();
+            Clock.ProcessFrame();
+
+            Add(new BeatContainer
+            {
+                Anchor = Anchor.BottomCentre,
+                Origin = Anchor.BottomCentre,
+            });
+
+            Add(mc = new MusicController
+            {
+                Origin = Anchor.TopRight,
+                Anchor = Anchor.TopRight,
+            });
+            mc.State = Visibility.Visible;
+        }
+
+        private class BeatContainer : BeatSyncedContainer
+        {
+            private const int flash_layer_heigth = 150;
+
+            private readonly InfoString timingPointCount;
+            private readonly InfoString currentTimingPoint;
+            private readonly InfoString beatCount;
+            private readonly InfoString currentBeat;
+            private readonly InfoString beatsPerMinute;
+            private readonly InfoString beatLength;
+
+            private readonly Box flashLayer;
+
+            public BeatContainer()
+            {
+                RelativeSizeAxes = Axes.X;
+                AutoSizeAxes = Axes.Y;
+                Children = new Drawable[]
+                {
+                    new FillFlowContainer
+                    {
+                        Name = @"Info Layer",
+                        Anchor = Anchor.BottomLeft,
+                        Origin = Anchor.BottomLeft,
+                        Direction = FillDirection.Vertical,
+                        AutoSizeAxes = Axes.Both,
+                        Margin = new MarginPadding { Bottom = flash_layer_heigth, },
+                        Children = new Drawable[]
+                        {
+                            timingPointCount = new InfoString(@"Timing points amount: "),
+                            currentTimingPoint = new InfoString(@"Current timing point: "),
+                            beatCount = new InfoString(@"Beats amount (in the current timing point): "),
+                            currentBeat = new InfoString(@"Current beat: "),
+                            beatsPerMinute = new InfoString(@"BPM: "),
+                            beatLength = new InfoString(@"Beat length: "),
+                        }
+                    },
+                    new Container
+                    {
+                        Name = @"Color indicator",
+                        Anchor = Anchor.BottomCentre,
+                        Origin = Anchor.BottomCentre,
+                        RelativeSizeAxes = Axes.X,
+                        Height = flash_layer_heigth,
+                        Children = new Drawable[]
+                        {
+                            new Box
+                            {
+                                RelativeSizeAxes = Axes.Both,
+                                Colour = Color4.Black,
+                            },
+                            flashLayer = new Box
+                            {
+                                RelativeSizeAxes = Axes.Both,
+                                Colour = Color4.White,
+                                Alpha = 0,
+                            }
+                        }
+                    }
+                };
+
+                Beatmap.ValueChanged += delegate
+                {
+                    timingPointCount.Value = 0;
+                    currentTimingPoint.Value = 0;
+                    beatCount.Value = 0;
+                    currentBeat.Value = 0;
+                    beatsPerMinute.Value = 0;
+                    beatLength.Value = 0;
+                };
+            }
+
+            private SortedList<TimingControlPoint> timingPoints => Beatmap.Value.Beatmap.ControlPointInfo.TimingPoints;
+            private TimingControlPoint getNextTimingPoint(TimingControlPoint current)
+            {
+                if (timingPoints[timingPoints.Count - 1] == current)
+                    return current;
+
+                return timingPoints[timingPoints.IndexOf(current) + 1];
+            }
+
+            private int calculateBeatCount(TimingControlPoint current)
+            {
+                if (timingPoints.IndexOf(current) + 1 == timingPoints.Count)
+                    return (int)Math.Ceiling((Beatmap.Value.Track.Length - current.Time) / current.BeatLength);
+
+                return (int)Math.Ceiling((getNextTimingPoint(current).Time - current.Time) / current.BeatLength);
+            }
+
+            protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes)
+            {
+                base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes);
+
+                timingPointCount.Value = timingPoints.Count;
+                currentTimingPoint.Value = timingPoints.IndexOf(timingPoint) + 1;
+                beatCount.Value = calculateBeatCount(timingPoint);
+                currentBeat.Value = beatIndex + 1;
+                beatsPerMinute.Value = (float)Math.Round(60000 / timingPoint.BeatLength, 1);
+                beatLength.Value = (float)timingPoint.BeatLength;
+
+                flashLayer.ClearTransforms();
+                flashLayer.FadeTo(1);
+                flashLayer.FadeTo(0, timingPoint.BeatLength);
+            }
+        }
+
+        private class InfoString : FillFlowContainer
+        {
+            private const int text_size = 20;
+            private const int margin = 7;
+
+            private readonly OsuSpriteText valueText;
+
+            private float? value;
+            public float Value
+            {
+                set
+                {
+                    if (value == this.value) return;
+                    this.value = value;
+
+                    valueText.Text = value.ToString(CultureInfo.CurrentCulture);
+                }
+            }
+
+            public InfoString(string header)
+            {
+                AutoSizeAxes = Axes.Both;
+                Direction = FillDirection.Horizontal;
+                Add(new OsuSpriteText { Text = header, TextSize = text_size });
+                Add(valueText = new OsuSpriteText() { TextSize = text_size });
+                Margin = new MarginPadding { Vertical = margin, };
+            }
+        }
+    }
+}

From 608f3fe8c5d5744da212d552f7e755d5b9494cab Mon Sep 17 00:00:00 2001
From: EVAST9919 <megaman9919@gmail.com>
Date: Fri, 23 Jun 2017 08:41:48 +0300
Subject: [PATCH 02/41] oops

---
 osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj | 1 +
 1 file changed, 1 insertion(+)

diff --git a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj
index de84e567d2..bd333c4df9 100644
--- a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj
+++ b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj
@@ -187,6 +187,7 @@
   <ItemGroup>
     <Compile Include="AutomatedVisualTestGame.cs" />
     <Compile Include="Program.cs" />
+    <Compile Include="Tests\TestCaseBeatSyncedContainer.cs" />
     <Compile Include="Tests\TestCaseChatDisplay.cs" />
     <Compile Include="Tests\TestCaseBeatmapDetails.cs" />
     <Compile Include="Tests\TestCaseContextMenu.cs" />

From a59af5b0054a10c2f5f1f2b89bccaf37c56b8fa6 Mon Sep 17 00:00:00 2001
From: EVAST9919 <megaman9919@gmail.com>
Date: Fri, 23 Jun 2017 10:01:28 +0300
Subject: [PATCH 03/41] Applied suggested changes

---
 .../Tests/TestCaseBeatSyncedContainer.cs      | 20 +++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs b/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
index a8fa8bf218..d70e60cd93 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
@@ -57,7 +57,7 @@ namespace osu.Desktop.VisualTests.Tests
             private readonly InfoString beatCount;
             private readonly InfoString currentBeat;
             private readonly InfoString beatsPerMinute;
-            private readonly InfoString beatLength;
+            private readonly InfoString adjustedBeatLength;
 
             private readonly Box flashLayer;
 
@@ -77,12 +77,12 @@ namespace osu.Desktop.VisualTests.Tests
                         Margin = new MarginPadding { Bottom = flash_layer_heigth, },
                         Children = new Drawable[]
                         {
-                            timingPointCount = new InfoString(@"Timing points amount: "),
-                            currentTimingPoint = new InfoString(@"Current timing point: "),
-                            beatCount = new InfoString(@"Beats amount (in the current timing point): "),
-                            currentBeat = new InfoString(@"Current beat: "),
-                            beatsPerMinute = new InfoString(@"BPM: "),
-                            beatLength = new InfoString(@"Beat length: "),
+                            timingPointCount = new InfoString(@"Timing points amount"),
+                            currentTimingPoint = new InfoString(@"Current timing point"),
+                            beatCount = new InfoString(@"Beats amount (in the current timing point)"),
+                            currentBeat = new InfoString(@"Current beat"),
+                            beatsPerMinute = new InfoString(@"BPM"),
+                            adjustedBeatLength = new InfoString(@"Beat length"),
                         }
                     },
                     new Container
@@ -116,7 +116,7 @@ namespace osu.Desktop.VisualTests.Tests
                     beatCount.Value = 0;
                     currentBeat.Value = 0;
                     beatsPerMinute.Value = 0;
-                    beatLength.Value = 0;
+                    adjustedBeatLength.Value = 0;
                 };
             }
 
@@ -146,7 +146,7 @@ namespace osu.Desktop.VisualTests.Tests
                 beatCount.Value = calculateBeatCount(timingPoint);
                 currentBeat.Value = beatIndex + 1;
                 beatsPerMinute.Value = (float)Math.Round(60000 / timingPoint.BeatLength, 1);
-                beatLength.Value = (float)timingPoint.BeatLength;
+                adjustedBeatLength.Value = (float)timingPoint.BeatLength;
 
                 flashLayer.ClearTransforms();
                 flashLayer.FadeTo(1);
@@ -177,7 +177,7 @@ namespace osu.Desktop.VisualTests.Tests
             {
                 AutoSizeAxes = Axes.Both;
                 Direction = FillDirection.Horizontal;
-                Add(new OsuSpriteText { Text = header, TextSize = text_size });
+                Add(new OsuSpriteText { Text = header + @": ", TextSize = text_size });
                 Add(valueText = new OsuSpriteText() { TextSize = text_size });
                 Margin = new MarginPadding { Vertical = margin, };
             }

From 3150bdb54b75d33b76a98f92dd1dd8fed63ee7ba Mon Sep 17 00:00:00 2001
From: EVAST9919 <megaman9919@gmail.com>
Date: Fri, 23 Jun 2017 14:56:43 +0300
Subject: [PATCH 04/41] Fixed wrong display string

---
 osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs b/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
index d70e60cd93..c0d2b04bcb 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
@@ -82,7 +82,7 @@ namespace osu.Desktop.VisualTests.Tests
                             beatCount = new InfoString(@"Beats amount (in the current timing point)"),
                             currentBeat = new InfoString(@"Current beat"),
                             beatsPerMinute = new InfoString(@"BPM"),
-                            adjustedBeatLength = new InfoString(@"Beat length"),
+                            adjustedBeatLength = new InfoString(@"Adjusted beat length"),
                         }
                     },
                     new Container

From ba783f984cb964cc6317126c33bb0742405b7980 Mon Sep 17 00:00:00 2001
From: MrTheMake <marc.stephan96@hotmail.de>
Date: Sat, 24 Jun 2017 13:36:57 +0200
Subject: [PATCH 05/41] Change usage of ScrollIntoView to ScrollTo in the
 setttings overlay

---
 osu.Game/Overlays/SettingsOverlay.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/osu.Game/Overlays/SettingsOverlay.cs b/osu.Game/Overlays/SettingsOverlay.cs
index 88f4599383..5677bbcad9 100644
--- a/osu.Game/Overlays/SettingsOverlay.cs
+++ b/osu.Game/Overlays/SettingsOverlay.cs
@@ -93,7 +93,7 @@ namespace osu.Game.Overlays
                         new SidebarButton
                         {
                             Section = section,
-                            Action = sectionsContainer.ScrollContainer.ScrollIntoView,
+                            Action = sectionsContainer.ScrollContainer.ScrollTo,
                         }
                     ).ToArray()
                 }

From d914a1b00ef20bbc88082d3760775a4b4a363252 Mon Sep 17 00:00:00 2001
From: MrTheMake <marc.stephan96@hotmail.de>
Date: Sat, 24 Jun 2017 13:47:34 +0200
Subject: [PATCH 06/41] Added animation parameter

---
 osu.Game/Overlays/Settings/SidebarButton.cs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/osu.Game/Overlays/Settings/SidebarButton.cs b/osu.Game/Overlays/Settings/SidebarButton.cs
index 309216dd91..8d5e0e96b7 100644
--- a/osu.Game/Overlays/Settings/SidebarButton.cs
+++ b/osu.Game/Overlays/Settings/SidebarButton.cs
@@ -22,7 +22,7 @@ namespace osu.Game.Overlays.Settings
         private readonly Box backgroundBox;
         private readonly Box selectionIndicator;
         private readonly Container text;
-        public Action<SettingsSection> Action;
+        public Action<SettingsSection, bool> Action;
 
         private SettingsSection section;
         public SettingsSection Section
@@ -112,7 +112,7 @@ namespace osu.Game.Overlays.Settings
 
         protected override bool OnClick(InputState state)
         {
-            Action?.Invoke(section);
+            Action?.Invoke(section, true);
             backgroundBox.FlashColour(Color4.White, 400);
             return true;
         }

From 40225238d96b78e1544f1f18721211d0174fb422 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thomas=20M=C3=BCller?= <thomas94@gmx.net>
Date: Wed, 28 Jun 2017 12:24:23 +0300
Subject: [PATCH 07/41] Set RelativeSizeAxes for updated FillMode behavior

---
 osu-framework                                        | 2 +-
 osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs      | 1 +
 osu.Game/Graphics/Backgrounds/Background.cs          | 1 +
 osu.Game/Overlays/Direct/DirectPanel.cs              | 1 +
 osu.Game/Overlays/MusicController.cs                 | 1 +
 osu.Game/Screens/Multiplayer/RoomInspector.cs        | 1 +
 osu.Game/Screens/Play/PlayerLoader.cs                | 1 +
 osu.Game/Screens/Ranking/Results.cs                  | 1 +
 osu.Game/Screens/Ranking/ResultsPageScore.cs         | 1 +
 osu.Game/Screens/Select/BeatmapInfoWedge.cs          | 1 +
 osu.Game/Screens/Select/Leaderboards/DrawableRank.cs | 1 +
 osu.Game/Screens/Tournament/Drawings.cs              | 1 +
 osu.Game/Screens/Tournament/Group.cs                 | 2 +-
 osu.Game/Users/Avatar.cs                             | 1 +
 osu.Game/Users/UserPanel.cs                          | 1 +
 15 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/osu-framework b/osu-framework
index a5e66079b9..3fffad110c 160000
--- a/osu-framework
+++ b/osu-framework
@@ -1 +1 @@
-Subproject commit a5e66079b9df3cf74a8bd1431c1cb7faad3c4d9f
+Subproject commit 3fffad110c0d019146944735ac2dcb8a37f98f8b
diff --git a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs
index 1ac6261621..b59dbac722 100644
--- a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs
+++ b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs
@@ -93,6 +93,7 @@ namespace osu.Game.Beatmaps.Drawables
                 {
                     new BeatmapBackgroundSprite(working)
                     {
+                        RelativeSizeAxes = Axes.Both,
                         Anchor = Anchor.Centre,
                         Origin = Anchor.Centre,
                         FillMode = FillMode.Fill,
diff --git a/osu.Game/Graphics/Backgrounds/Background.cs b/osu.Game/Graphics/Backgrounds/Background.cs
index 7c47635276..8eb2ddc0ab 100644
--- a/osu.Game/Graphics/Backgrounds/Background.cs
+++ b/osu.Game/Graphics/Backgrounds/Background.cs
@@ -26,6 +26,7 @@ namespace osu.Game.Graphics.Backgrounds
 
             Add(Sprite = new Sprite
             {
+                RelativeSizeAxes = Axes.Both,
                 Anchor = Anchor.Centre,
                 Origin = Anchor.Centre,
                 Colour = Color4.DarkGray,
diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs
index f8acad1f59..3c708bff67 100644
--- a/osu.Game/Overlays/Direct/DirectPanel.cs
+++ b/osu.Game/Overlays/Direct/DirectPanel.cs
@@ -38,6 +38,7 @@ namespace osu.Game.Overlays.Direct
         {
             return new AsyncLoadWrapper(new BeatmapBackgroundSprite(new OnlineWorkingBeatmap(SetInfo.Beatmaps.FirstOrDefault(), textures, null))
             {
+                RelativeSizeAxes = Axes.Both,
                 FillMode = FillMode.Fill,
                 OnLoadComplete = d => d.FadeInFromZero(400, EasingTypes.Out),
             }) { RelativeSizeAxes = Axes.Both };
diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs
index e1e920ec0f..181046f3ff 100644
--- a/osu.Game/Overlays/MusicController.cs
+++ b/osu.Game/Overlays/MusicController.cs
@@ -397,6 +397,7 @@ namespace osu.Game.Overlays
                 {
                     sprite = new Sprite
                     {
+                        RelativeSizeAxes = Axes.Both,
                         Colour = OsuColour.Gray(150),
                         FillMode = FillMode.Fill,
                     },
diff --git a/osu.Game/Screens/Multiplayer/RoomInspector.cs b/osu.Game/Screens/Multiplayer/RoomInspector.cs
index f9e015eceb..3a822be791 100644
--- a/osu.Game/Screens/Multiplayer/RoomInspector.cs
+++ b/osu.Game/Screens/Multiplayer/RoomInspector.cs
@@ -438,6 +438,7 @@ namespace osu.Game.Screens.Multiplayer
                 {
                     new AsyncLoadWrapper(new BeatmapBackgroundSprite(new OnlineWorkingBeatmap(value, textures, null))
                     {
+                        RelativeSizeAxes = Axes.Both,
                         Anchor = Anchor.Centre,
                         Origin = Anchor.Centre,
                         FillMode = FillMode.Fill,
diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs
index 726397a3b1..c8ebb1f436 100644
--- a/osu.Game/Screens/Play/PlayerLoader.cs
+++ b/osu.Game/Screens/Play/PlayerLoader.cs
@@ -227,6 +227,7 @@ namespace osu.Game.Screens.Play
                                 {
                                     new Sprite
                                     {
+                                        RelativeSizeAxes = Axes.Both,
                                         Texture = beatmap?.Background,
                                         Origin = Anchor.Centre,
                                         Anchor = Anchor.Centre,
diff --git a/osu.Game/Screens/Ranking/Results.cs b/osu.Game/Screens/Ranking/Results.cs
index 2bff535603..dac83536ed 100644
--- a/osu.Game/Screens/Ranking/Results.cs
+++ b/osu.Game/Screens/Ranking/Results.cs
@@ -163,6 +163,7 @@ namespace osu.Game.Screens.Ranking
                                     {
                                         new Sprite
                                         {
+                                            RelativeSizeAxes = Axes.Both,
                                             Alpha = 0.2f,
                                             Texture = Beatmap?.Background,
                                             Anchor = Anchor.Centre,
diff --git a/osu.Game/Screens/Ranking/ResultsPageScore.cs b/osu.Game/Screens/Ranking/ResultsPageScore.cs
index 15e8e4bfcd..96e63585bf 100644
--- a/osu.Game/Screens/Ranking/ResultsPageScore.cs
+++ b/osu.Game/Screens/Ranking/ResultsPageScore.cs
@@ -343,6 +343,7 @@ namespace osu.Game.Screens.Ranking
                 {
                     cover = new Sprite
                     {
+                        RelativeSizeAxes = Axes.Both,
                         FillMode = FillMode.Fill,
                         Anchor = Anchor.Centre,
                         Origin = Anchor.Centre,
diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs
index 264fe6643b..42f9598096 100644
--- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs
+++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs
@@ -152,6 +152,7 @@ namespace osu.Game.Screens.Select
                             // Zoomed-in and cropped beatmap background
                             new BeatmapBackgroundSprite(beatmap)
                             {
+                                RelativeSizeAxes = Axes.Both,
                                 Anchor = Anchor.Centre,
                                 Origin = Anchor.Centre,
                                 FillMode = FillMode.Fill,
diff --git a/osu.Game/Screens/Select/Leaderboards/DrawableRank.cs b/osu.Game/Screens/Select/Leaderboards/DrawableRank.cs
index 647398db9e..6329729687 100644
--- a/osu.Game/Screens/Select/Leaderboards/DrawableRank.cs
+++ b/osu.Game/Screens/Select/Leaderboards/DrawableRank.cs
@@ -31,6 +31,7 @@ namespace osu.Game.Screens.Select.Leaderboards
             {
                 rankSprite = new Sprite
                 {
+                    RelativeSizeAxes = Axes.Both,
                     Anchor = Anchor.Centre,
                     Origin = Anchor.Centre,
                     FillMode = FillMode.Fit
diff --git a/osu.Game/Screens/Tournament/Drawings.cs b/osu.Game/Screens/Tournament/Drawings.cs
index 7efb86a403..246fa17e85 100644
--- a/osu.Game/Screens/Tournament/Drawings.cs
+++ b/osu.Game/Screens/Tournament/Drawings.cs
@@ -82,6 +82,7 @@ namespace osu.Game.Screens.Tournament
                 },
                 new Sprite
                 {
+                    RelativeSizeAxes = Axes.Both,
                     FillMode = FillMode.Fill,
                     Texture = textures.Get(@"Backgrounds/Drawings/background.png")
                 },
diff --git a/osu.Game/Screens/Tournament/Group.cs b/osu.Game/Screens/Tournament/Group.cs
index 441a5c7bcd..bd13ced2cd 100644
--- a/osu.Game/Screens/Tournament/Group.cs
+++ b/osu.Game/Screens/Tournament/Group.cs
@@ -151,9 +151,9 @@ namespace osu.Game.Screens.Tournament
                         {
                             flagSprite = new Sprite
                             {
+                                RelativeSizeAxes = Axes.Both,
                                 Anchor = Anchor.TopCentre,
                                 Origin = Anchor.TopCentre,
-
                                 FillMode = FillMode.Fit
                             },
                             new OsuSpriteText
diff --git a/osu.Game/Users/Avatar.cs b/osu.Game/Users/Avatar.cs
index b032187624..5d518f1780 100644
--- a/osu.Game/Users/Avatar.cs
+++ b/osu.Game/Users/Avatar.cs
@@ -31,6 +31,7 @@ namespace osu.Game.Users
 
             Add(new Sprite
             {
+                RelativeSizeAxes = Axes.Both,
                 Texture = texture,
                 FillMode = FillMode.Fit,
                 Anchor = Anchor.Centre,
diff --git a/osu.Game/Users/UserPanel.cs b/osu.Game/Users/UserPanel.cs
index 8cff3517a3..881aaf2e07 100644
--- a/osu.Game/Users/UserPanel.cs
+++ b/osu.Game/Users/UserPanel.cs
@@ -46,6 +46,7 @@ namespace osu.Game.Users
             {
                 new AsyncLoadWrapper(new CoverBackgroundSprite(user)
                 {
+                    RelativeSizeAxes = Axes.Both,
                     Anchor = Anchor.Centre,
                     Origin = Anchor.Centre,
                     FillMode = FillMode.Fill,

From 912cac318f1bcbc4fa9c12918203b4c743b7dbf5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thomas=20M=C3=BCller?= <thomas94@gmx.net>
Date: Sat, 8 Jul 2017 12:25:18 +0300
Subject: [PATCH 08/41] Update framework

---
 osu-framework | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/osu-framework b/osu-framework
index af9ffbd8b9..8dc785a0ae 160000
--- a/osu-framework
+++ b/osu-framework
@@ -1 +1 @@
-Subproject commit af9ffbd8b945e526801c469dd55464363e502962
+Subproject commit 8dc785a0aecfb6df53496eff5bd9f961ff8deee6

From 45d07e39c18a8c4836ea06101dd76c0b7ca4fd2a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thomas=20M=C3=BCller?= <thomas94@gmx.net>
Date: Sat, 8 Jul 2017 12:41:15 +0300
Subject: [PATCH 09/41] Update framework & change logic slightly

---
 osu-framework                               | 2 +-
 osu.Game/Overlays/Settings/SidebarButton.cs | 4 ++--
 osu.Game/Overlays/SettingsOverlay.cs        | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/osu-framework b/osu-framework
index af9ffbd8b9..8dc785a0ae 160000
--- a/osu-framework
+++ b/osu-framework
@@ -1 +1 @@
-Subproject commit af9ffbd8b945e526801c469dd55464363e502962
+Subproject commit 8dc785a0aecfb6df53496eff5bd9f961ff8deee6
diff --git a/osu.Game/Overlays/Settings/SidebarButton.cs b/osu.Game/Overlays/Settings/SidebarButton.cs
index 8d5e0e96b7..309216dd91 100644
--- a/osu.Game/Overlays/Settings/SidebarButton.cs
+++ b/osu.Game/Overlays/Settings/SidebarButton.cs
@@ -22,7 +22,7 @@ namespace osu.Game.Overlays.Settings
         private readonly Box backgroundBox;
         private readonly Box selectionIndicator;
         private readonly Container text;
-        public Action<SettingsSection, bool> Action;
+        public Action<SettingsSection> Action;
 
         private SettingsSection section;
         public SettingsSection Section
@@ -112,7 +112,7 @@ namespace osu.Game.Overlays.Settings
 
         protected override bool OnClick(InputState state)
         {
-            Action?.Invoke(section, true);
+            Action?.Invoke(section);
             backgroundBox.FlashColour(Color4.White, 400);
             return true;
         }
diff --git a/osu.Game/Overlays/SettingsOverlay.cs b/osu.Game/Overlays/SettingsOverlay.cs
index fc9dddf121..4a5a0de890 100644
--- a/osu.Game/Overlays/SettingsOverlay.cs
+++ b/osu.Game/Overlays/SettingsOverlay.cs
@@ -93,7 +93,7 @@ namespace osu.Game.Overlays
                         new SidebarButton
                         {
                             Section = section,
-                            Action = sectionsContainer.ScrollContainer.ScrollTo,
+                            Action = b => sectionsContainer.ScrollContainer.ScrollTo(b),
                         }
                     ).ToArray()
                 }

From 2c8b8c3f9c7bf829e5dddbc81d6997d09daa69c6 Mon Sep 17 00:00:00 2001
From: Dean Herbert <pe@ppy.sh>
Date: Sun, 9 Jul 2017 18:23:34 +0900
Subject: [PATCH 10/41] Update loop logic in line with framework changes

---
 .../Tests/TestCaseContextMenu.cs              |  57 ++++-----
 .../Tests/TestCaseNotificationManager.cs      |   2 +-
 .../Objects/Drawables/Pieces/SliderBouncer.cs |   4 +-
 .../Containers/BeatSyncedContainer.cs         |  11 +-
 .../UserInterface/LoadingAnimation.cs         |   5 +-
 .../Overlays/Notifications/Notification.cs    |  25 ++--
 osu.Game/Screens/Menu/Button.cs               | 108 +++++-------------
 7 files changed, 68 insertions(+), 144 deletions(-)

diff --git a/osu.Desktop.VisualTests/Tests/TestCaseContextMenu.cs b/osu.Desktop.VisualTests/Tests/TestCaseContextMenu.cs
index 6c0da885ac..c46aacc91a 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseContextMenu.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseContextMenu.cs
@@ -21,10 +21,10 @@ namespace osu.Desktop.VisualTests.Tests
         private const int start_time = 0;
         private const int duration = 1000;
 
+        private Container container;
+
         public TestCaseContextMenu()
         {
-            MyContextMenuContainer container;
-
             Add(container = new MyContextMenuContainer
             {
                 Size = new Vector2(200),
@@ -54,43 +54,26 @@ namespace osu.Desktop.VisualTests.Tests
                     }
                 }
             });
+        }
 
-            container.Transforms.Add(new TransformPosition
+        protected override void LoadComplete()
+        {
+            base.LoadComplete();
+
+            using (container.BeginLoopedSequece())
             {
-                StartValue = Vector2.Zero,
-                EndValue = new Vector2(0, 100),
-                StartTime = start_time,
-                EndTime = start_time + duration,
-                LoopCount = -1,
-                LoopDelay = duration * 3
-            });
-            container.Transforms.Add(new TransformPosition
-            {
-                StartValue = new Vector2(0, 100),
-                EndValue = new Vector2(100, 100),
-                StartTime = start_time + duration,
-                EndTime = start_time + duration * 2,
-                LoopCount = -1,
-                LoopDelay = duration * 3
-            });
-            container.Transforms.Add(new TransformPosition
-            {
-                StartValue = new Vector2(100, 100),
-                EndValue = new Vector2(100, 0),
-                StartTime = start_time + duration * 2,
-                EndTime = start_time + duration * 3,
-                LoopCount = -1,
-                LoopDelay = duration * 3
-            });
-            container.Transforms.Add(new TransformPosition
-            {
-                StartValue = new Vector2(100, 0),
-                EndValue = Vector2.Zero,
-                StartTime = start_time + duration * 3,
-                EndTime = start_time + duration * 4,
-                LoopCount = -1,
-                LoopDelay = duration * 3
-            });
+                container.MoveTo(new Vector2(0, 100), duration);
+                using (container.BeginDelayedSequence(duration))
+                {
+                    container.MoveTo(new Vector2(100, 100), duration);
+                    using (container.BeginDelayedSequence(duration))
+                    {
+                        container.MoveTo(new Vector2(100, 0), duration);
+                        using (container.BeginDelayedSequence(duration))
+                            container.MoveTo(Vector2.Zero, duration);
+                    }
+                }
+            }
         }
 
         private class MyContextMenuContainer : Container, IHasContextMenu
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseNotificationManager.cs b/osu.Desktop.VisualTests/Tests/TestCaseNotificationManager.cs
index 4ba50c8220..bb2aa9ab0f 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseNotificationManager.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseNotificationManager.cs
@@ -34,7 +34,7 @@ namespace osu.Desktop.VisualTests.Tests
             AddStep(@"simple #2", sendNotification2);
             AddStep(@"progress #1", sendProgress1);
             AddStep(@"progress #2", sendProgress2);
-            AddStep(@"barrage", () => sendBarrage());
+            //AddStep(@"barrage", () => sendBarrage());
         }
 
         private void sendBarrage(int remaining = 100)
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBouncer.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBouncer.cs
index 65679dd7d3..12d8193641 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBouncer.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBouncer.cs
@@ -37,8 +37,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
         protected override void LoadComplete()
         {
             base.LoadComplete();
-            icon.RotateTo(360, 1000);
-            icon.Loop();
+            using (icon.BeginLoopedSequece())
+                icon.RotateTo(360, 1000);
         }
 
         public void UpdateProgress(double progress, int repeat)
diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs
index c0defceac0..68b7637e10 100644
--- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs
+++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs
@@ -23,6 +23,11 @@ namespace osu.Game.Graphics.Containers
         /// </summary>
         protected double EarlyActivationMilliseconds;
 
+        /// <summary>
+        /// The time in milliseconds until the next beat.
+        /// </summary>
+        public double TimeUntilNextBeat { get; private set; }
+
         protected override void Update()
         {
             if (Beatmap.Value?.Track == null)
@@ -42,12 +47,12 @@ namespace osu.Game.Graphics.Containers
             if (currentTrackTime < timingPoint.Time)
                 beatIndex--;
 
+            TimeUntilNextBeat = (timingPoint.Time - currentTrackTime) % timingPoint.BeatLength;
+
             if (timingPoint == lastTimingPoint && beatIndex == lastBeat)
                 return;
 
-            double offsetFromBeat = (timingPoint.Time - currentTrackTime) % timingPoint.BeatLength;
-
-            using (BeginDelayedSequence(offsetFromBeat, true))
+            using (BeginDelayedSequence(TimeUntilNextBeat, true))
                 OnNewBeat(beatIndex, timingPoint, effectPoint, Beatmap.Value.Track.CurrentAmplitudes);
 
             lastBeat = beatIndex;
diff --git a/osu.Game/Graphics/UserInterface/LoadingAnimation.cs b/osu.Game/Graphics/UserInterface/LoadingAnimation.cs
index 27a888f0b5..59e08ba004 100644
--- a/osu.Game/Graphics/UserInterface/LoadingAnimation.cs
+++ b/osu.Game/Graphics/UserInterface/LoadingAnimation.cs
@@ -34,9 +34,8 @@ namespace osu.Game.Graphics.UserInterface
         {
             base.LoadComplete();
 
-            spinner.RotateTo(360, 2000);
-            using (spinner.BeginDelayedSequence(2000))
-                spinner.Loop();
+            using (spinner.BeginLoopedSequece())
+                spinner.RotateTo(360, 2000);
         }
 
         private const float transition_duration = 500;
diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs
index 3380c61385..2a9297c443 100644
--- a/osu.Game/Overlays/Notifications/Notification.cs
+++ b/osu.Game/Overlays/Notifications/Notification.cs
@@ -203,6 +203,8 @@ namespace osu.Game.Overlays.Notifications
                 get { return pulsate; }
                 set
                 {
+                    if (pulsate == value) return;
+
                     pulsate = value;
 
                     pulsateLayer.ClearTransforms();
@@ -211,25 +213,12 @@ namespace osu.Game.Overlays.Notifications
                     if (pulsate)
                     {
                         const float length = 1000;
-                        pulsateLayer.Transforms.Add(new TransformAlpha
+                        using (pulsateLayer.BeginLoopedSequece(length / 2))
                         {
-                            StartTime = Time.Current,
-                            EndTime = Time.Current + length,
-                            StartValue = 1,
-                            EndValue = 0.4f,
-                            Easing = EasingTypes.In
-                        });
-                        pulsateLayer.Transforms.Add(new TransformAlpha
-                        {
-                            StartTime = Time.Current + length,
-                            EndTime = Time.Current + length * 2,
-                            StartValue = 0.4f,
-                            EndValue = 1,
-                            Easing = EasingTypes.Out
-                        });
-
-                        //todo: figure why we can't add arbitrary delays at the end of loop.
-                        pulsateLayer.Loop(length * 2);
+                            pulsateLayer.FadeTo(0.4f, length, EasingTypes.In);
+                            using (pulsateLayer.BeginDelayedSequence(length))
+                                pulsateLayer.FadeTo(1, length, EasingTypes.Out);
+                        }
                     }
                 }
             }
diff --git a/osu.Game/Screens/Menu/Button.cs b/osu.Game/Screens/Menu/Button.cs
index c8739f8894..8dad83bd0e 100644
--- a/osu.Game/Screens/Menu/Button.cs
+++ b/osu.Game/Screens/Menu/Button.cs
@@ -9,7 +9,6 @@ using osu.Framework.Audio.Sample;
 using osu.Framework.Graphics;
 using osu.Framework.Graphics.Containers;
 using osu.Framework.Graphics.Shapes;
-using osu.Framework.Graphics.Transforms;
 using osu.Framework.Input;
 using osu.Game.Graphics;
 using osu.Game.Graphics.Sprites;
@@ -17,6 +16,9 @@ using OpenTK;
 using OpenTK.Graphics;
 using OpenTK.Input;
 using osu.Framework.Extensions.Color4Extensions;
+using osu.Game.Graphics.Containers;
+using osu.Framework.Audio.Track;
+using osu.Game.Beatmaps.ControlPoints;
 
 namespace osu.Game.Screens.Menu
 {
@@ -24,7 +26,7 @@ namespace osu.Game.Screens.Menu
     /// Button designed specifically for the osu!next main menu.
     /// In order to correctly flow, we have to use a negative margin on the parent container (due to the parallelogram shape).
     /// </summary>
-    public class Button : Container, IStateful<ButtonState>
+    public class Button : BeatSyncedContainer, IStateful<ButtonState>
     {
         private readonly Container iconText;
         private readonly Container box;
@@ -117,6 +119,27 @@ namespace osu.Game.Screens.Menu
             };
         }
 
+        protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes)
+        {
+            base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes);
+
+            if (!IsHovered) return;
+
+            bool rightward = beatIndex % 2 == 1;
+            double duration = timingPoint.BeatLength / 2;
+
+            icon.RotateTo(rightward ? 10 : -10, duration * 2, EasingTypes.InOutSine);
+
+            icon.MoveToY(-10, duration, EasingTypes.Out);
+            icon.ScaleTo(Vector2.One, duration, EasingTypes.Out);
+
+            using (icon.BeginDelayedSequence(duration))
+            {
+                icon.MoveToY(0, duration, EasingTypes.In);
+                icon.ScaleTo(new Vector2(1, 0.9f), duration, EasingTypes.In);
+            }
+        }
+
         protected override bool OnHover(InputState state)
         {
             if (State != ButtonState.Expanded) return true;
@@ -125,85 +148,11 @@ namespace osu.Game.Screens.Menu
 
             box.ScaleTo(new Vector2(1.5f, 1), 500, EasingTypes.OutElastic);
 
-            int duration = 0; //(int)(Game.Audio.BeatLength / 2);
-            if (duration == 0) duration = 250;
+            double duration = TimeUntilNextBeat;
 
             icon.ClearTransforms();
-
-            icon.ScaleTo(1, 500, EasingTypes.OutElasticHalf);
-
-            const double offset = 0; //(1 - Game.Audio.SyncBeatProgress) * duration;
-            double startTime = Time.Current + offset;
-
-            icon.RotateTo(10, offset, EasingTypes.InOutSine);
-            icon.ScaleTo(new Vector2(1, 0.9f), offset, EasingTypes.Out);
-
-            icon.Transforms.Add(new TransformRotation
-            {
-                StartValue = -10,
-                EndValue = 10,
-                StartTime = startTime,
-                EndTime = startTime + duration * 2,
-                Easing = EasingTypes.InOutSine,
-                LoopCount = -1,
-                LoopDelay = duration * 2
-            });
-
-            icon.Transforms.Add(new TransformPosition
-            {
-                StartValue = Vector2.Zero,
-                EndValue = new Vector2(0, -10),
-                StartTime = startTime,
-                EndTime = startTime + duration,
-                Easing = EasingTypes.Out,
-                LoopCount = -1,
-                LoopDelay = duration
-            });
-
-            icon.Transforms.Add(new TransformScale
-            {
-                StartValue = new Vector2(1, 0.9f),
-                EndValue = Vector2.One,
-                StartTime = startTime,
-                EndTime = startTime + duration,
-                Easing = EasingTypes.Out,
-                LoopCount = -1,
-                LoopDelay = duration
-            });
-
-            icon.Transforms.Add(new TransformPosition
-            {
-                StartValue = new Vector2(0, -10),
-                EndValue = Vector2.Zero,
-                StartTime = startTime + duration,
-                EndTime = startTime + duration * 2,
-                Easing = EasingTypes.In,
-                LoopCount = -1,
-                LoopDelay = duration
-            });
-
-            icon.Transforms.Add(new TransformScale
-            {
-                StartValue = Vector2.One,
-                EndValue = new Vector2(1, 0.9f),
-                StartTime = startTime + duration,
-                EndTime = startTime + duration * 2,
-                Easing = EasingTypes.In,
-                LoopCount = -1,
-                LoopDelay = duration
-            });
-
-            icon.Transforms.Add(new TransformRotation
-            {
-                StartValue = 10,
-                EndValue = -10,
-                StartTime = startTime + duration * 2,
-                EndTime = startTime + duration * 4,
-                Easing = EasingTypes.InOutSine,
-                LoopCount = -1,
-                LoopDelay = duration * 2
-            });
-
+            icon.RotateTo(10, duration, EasingTypes.InOutSine);
+            icon.ScaleTo(new Vector2(1, 0.9f), duration, EasingTypes.Out);
             return true;
         }
 
@@ -212,7 +161,6 @@ namespace osu.Game.Screens.Menu
             icon.ClearTransforms();
             icon.RotateTo(0, 500, EasingTypes.Out);
             icon.MoveTo(Vector2.Zero, 500, EasingTypes.Out);
-            icon.ScaleTo(0.7f, 500, EasingTypes.OutElasticHalf);
             icon.ScaleTo(Vector2.One, 200, EasingTypes.Out);
 
             if (State == ButtonState.Expanded)

From 105d57a697530bd743d7a4cf206594bd93c093c8 Mon Sep 17 00:00:00 2001
From: EVAST9919 <megaman9919@gmail.com>
Date: Sun, 9 Jul 2017 13:39:48 +0300
Subject: [PATCH 11/41] Update Testcase inline with framework

---
 .../Tests/TestCaseBeatSyncedContainer.cs          | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs b/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
index c0d2b04bcb..9bf307b1ce 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
@@ -15,6 +15,7 @@ using osu.Game.Graphics.Sprites;
 using osu.Framework.Lists;
 using System;
 using System.Globalization;
+using osu.Framework.Allocation;
 
 namespace osu.Desktop.VisualTests.Tests
 {
@@ -27,11 +28,6 @@ namespace osu.Desktop.VisualTests.Tests
         public TestCaseBeatSyncedContainer()
         {
             Clock = new FramedClock();
-        }
-
-        public override void Reset()
-        {
-            base.Reset();
             Clock.ProcessFrame();
 
             Add(new BeatContainer
@@ -45,7 +41,12 @@ namespace osu.Desktop.VisualTests.Tests
                 Origin = Anchor.TopRight,
                 Anchor = Anchor.TopRight,
             });
-            mc.State = Visibility.Visible;
+        }
+
+        [BackgroundDependencyLoader]
+        private void load()
+        {
+            mc.ToggleVisibility();
         }
 
         private class BeatContainer : BeatSyncedContainer
@@ -141,6 +142,8 @@ namespace osu.Desktop.VisualTests.Tests
             {
                 base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes);
 
+                if (beatIndex < 0) return;
+
                 timingPointCount.Value = timingPoints.Count;
                 currentTimingPoint.Value = timingPoints.IndexOf(timingPoint) + 1;
                 beatCount.Value = calculateBeatCount(timingPoint);

From bd45e1f1e741be4957a267562db1c2a2b89233f2 Mon Sep 17 00:00:00 2001
From: EVAST9919 <megaman9919@gmail.com>
Date: Sun, 9 Jul 2017 13:48:20 +0300
Subject: [PATCH 12/41] Make field readonly

---
 osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs b/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
index 9bf307b1ce..ffcc76e82c 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
@@ -23,7 +23,7 @@ namespace osu.Desktop.VisualTests.Tests
     {
         public override string Description => @"Tests beat synced containers.";
 
-        private MusicController mc;
+        private readonly MusicController mc;
 
         public TestCaseBeatSyncedContainer()
         {

From 62fc55521c0864a78c5cda8a7b82130b67e07079 Mon Sep 17 00:00:00 2001
From: EVAST9919 <megaman9919@gmail.com>
Date: Sun, 9 Jul 2017 13:54:38 +0300
Subject: [PATCH 13/41] Added background colour for better info visibility

---
 .../Tests/TestCaseBeatSyncedContainer.cs      | 35 +++++++++++++------
 1 file changed, 25 insertions(+), 10 deletions(-)

diff --git a/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs b/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
index ffcc76e82c..f5b96391dd 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
@@ -16,6 +16,7 @@ using osu.Framework.Lists;
 using System;
 using System.Globalization;
 using osu.Framework.Allocation;
+using osu.Framework.Extensions.Color4Extensions;
 
 namespace osu.Desktop.VisualTests.Tests
 {
@@ -68,22 +69,36 @@ namespace osu.Desktop.VisualTests.Tests
                 AutoSizeAxes = Axes.Y;
                 Children = new Drawable[]
                 {
-                    new FillFlowContainer
+                    new Container
                     {
                         Name = @"Info Layer",
                         Anchor = Anchor.BottomLeft,
                         Origin = Anchor.BottomLeft,
-                        Direction = FillDirection.Vertical,
                         AutoSizeAxes = Axes.Both,
-                        Margin = new MarginPadding { Bottom = flash_layer_heigth, },
+                        Margin = new MarginPadding { Bottom = flash_layer_heigth },
                         Children = new Drawable[]
                         {
-                            timingPointCount = new InfoString(@"Timing points amount"),
-                            currentTimingPoint = new InfoString(@"Current timing point"),
-                            beatCount = new InfoString(@"Beats amount (in the current timing point)"),
-                            currentBeat = new InfoString(@"Current beat"),
-                            beatsPerMinute = new InfoString(@"BPM"),
-                            adjustedBeatLength = new InfoString(@"Adjusted beat length"),
+                            new Box
+                            {
+                                RelativeSizeAxes = Axes.Both,
+                                Colour = Color4.Black.Opacity(150),
+                            },
+                            new FillFlowContainer
+                            {
+                                Anchor = Anchor.BottomLeft,
+                                Origin = Anchor.BottomLeft,
+                                AutoSizeAxes = Axes.Both,
+                                Direction = FillDirection.Vertical,
+                                Children = new Drawable[]
+                                {
+                                    timingPointCount = new InfoString(@"Timing points amount"),
+                                    currentTimingPoint = new InfoString(@"Current timing point"),
+                                    beatCount = new InfoString(@"Beats amount (in the current timing point)"),
+                                    currentBeat = new InfoString(@"Current beat"),
+                                    beatsPerMinute = new InfoString(@"BPM"),
+                                    adjustedBeatLength = new InfoString(@"Adjusted beat length"),
+                                }
+                            }
                         }
                     },
                     new Container
@@ -182,7 +197,7 @@ namespace osu.Desktop.VisualTests.Tests
                 Direction = FillDirection.Horizontal;
                 Add(new OsuSpriteText { Text = header + @": ", TextSize = text_size });
                 Add(valueText = new OsuSpriteText() { TextSize = text_size });
-                Margin = new MarginPadding { Vertical = margin, };
+                Margin = new MarginPadding { Vertical = margin, Horizontal = margin };
             }
         }
     }

From d533ac0e98bfb530ab4120f4b5219f9c917171e5 Mon Sep 17 00:00:00 2001
From: EVAST9919 <megaman9919@gmail.com>
Date: Sun, 9 Jul 2017 13:57:13 +0300
Subject: [PATCH 14/41] Simplify info margin

---
 osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs b/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
index f5b96391dd..88ed37ddb0 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
@@ -197,7 +197,7 @@ namespace osu.Desktop.VisualTests.Tests
                 Direction = FillDirection.Horizontal;
                 Add(new OsuSpriteText { Text = header + @": ", TextSize = text_size });
                 Add(valueText = new OsuSpriteText() { TextSize = text_size });
-                Margin = new MarginPadding { Vertical = margin, Horizontal = margin };
+                Margin = new MarginPadding(margin);
             }
         }
     }

From 8c40b808132bf0efed87065496d8ac8602bc0d5d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thomas=20M=C3=BCller?= <thomas94@gmx.net>
Date: Sun, 9 Jul 2017 19:33:23 +0300
Subject: [PATCH 15/41] Also display negative beats

---
 osu-framework                                                | 2 +-
 osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs | 2 --
 2 files changed, 1 insertion(+), 3 deletions(-)

diff --git a/osu-framework b/osu-framework
index 8dc785a0ae..1242968326 160000
--- a/osu-framework
+++ b/osu-framework
@@ -1 +1 @@
-Subproject commit 8dc785a0aecfb6df53496eff5bd9f961ff8deee6
+Subproject commit 1242968326461ec1d7e1fb6877b12658d7e1644c
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs b/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
index 88ed37ddb0..29eadfe26e 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
@@ -157,8 +157,6 @@ namespace osu.Desktop.VisualTests.Tests
             {
                 base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes);
 
-                if (beatIndex < 0) return;
-
                 timingPointCount.Value = timingPoints.Count;
                 currentTimingPoint.Value = timingPoints.IndexOf(timingPoint) + 1;
                 beatCount.Value = calculateBeatCount(timingPoint);

From 1f425c3be8b8cfdd35cf20f1f485c6a013e72b9d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thomas=20M=C3=BCller?= <thomas94@gmx.net>
Date: Sun, 9 Jul 2017 19:40:36 +0300
Subject: [PATCH 16/41] Simplify existing code

---
 .../Tests/TestCaseBeatSyncedContainer.cs          | 15 ++++-----------
 1 file changed, 4 insertions(+), 11 deletions(-)

diff --git a/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs b/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
index 29eadfe26e..05038f2d59 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
@@ -44,9 +44,9 @@ namespace osu.Desktop.VisualTests.Tests
             });
         }
 
-        [BackgroundDependencyLoader]
-        private void load()
+        protected override void LoadComplete()
         {
+            base.LoadComplete();
             mc.ToggleVisibility();
         }
 
@@ -147,7 +147,7 @@ namespace osu.Desktop.VisualTests.Tests
 
             private int calculateBeatCount(TimingControlPoint current)
             {
-                if (timingPoints.IndexOf(current) + 1 == timingPoints.Count)
+                if (timingPoints[timingPoints.Count - 1] == current)
                     return (int)Math.Ceiling((Beatmap.Value.Track.Length - current.Time) / current.BeatLength);
 
                 return (int)Math.Ceiling((getNextTimingPoint(current).Time - current.Time) / current.BeatLength);
@@ -177,16 +177,9 @@ namespace osu.Desktop.VisualTests.Tests
 
             private readonly OsuSpriteText valueText;
 
-            private float? value;
             public float Value
             {
-                set
-                {
-                    if (value == this.value) return;
-                    this.value = value;
-
-                    valueText.Text = value.ToString(CultureInfo.CurrentCulture);
-                }
+                set { valueText.Text = value.ToString(); }
             }
 
             public InfoString(string header)

From 934a585b9482ac8f34061ee2483d76083178f726 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thomas=20M=C3=BCller?= <thomas94@gmx.net>
Date: Sun, 9 Jul 2017 19:40:57 +0300
Subject: [PATCH 17/41] Better number formatting

---
 .../Tests/TestCaseBeatSyncedContainer.cs                  | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs b/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
index 05038f2d59..27c2467cb9 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
@@ -161,8 +161,8 @@ namespace osu.Desktop.VisualTests.Tests
                 currentTimingPoint.Value = timingPoints.IndexOf(timingPoint) + 1;
                 beatCount.Value = calculateBeatCount(timingPoint);
                 currentBeat.Value = beatIndex + 1;
-                beatsPerMinute.Value = (float)Math.Round(60000 / timingPoint.BeatLength, 1);
-                adjustedBeatLength.Value = (float)timingPoint.BeatLength;
+                beatsPerMinute.Value = 60000 / timingPoint.BeatLength;
+                adjustedBeatLength.Value = timingPoint.BeatLength;
 
                 flashLayer.ClearTransforms();
                 flashLayer.FadeTo(1);
@@ -177,9 +177,9 @@ namespace osu.Desktop.VisualTests.Tests
 
             private readonly OsuSpriteText valueText;
 
-            public float Value
+            public double Value
             {
-                set { valueText.Text = value.ToString(); }
+                set { valueText.Text = $"{value:G}"; }
             }
 
             public InfoString(string header)

From dedd4561a12e725ff68e3bcc990a319a92ad47e7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thomas=20M=C3=BCller?= <thomas94@gmx.net>
Date: Sun, 9 Jul 2017 19:41:36 +0300
Subject: [PATCH 18/41] Display indices rather than one-based numbers

---
 osu-framework                                                | 2 +-
 osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/osu-framework b/osu-framework
index 1242968326..3c76bce457 160000
--- a/osu-framework
+++ b/osu-framework
@@ -1 +1 @@
-Subproject commit 1242968326461ec1d7e1fb6877b12658d7e1644c
+Subproject commit 3c76bce45762765b7268f8036da681a788f756b9
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs b/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
index 27c2467cb9..95e24dd6fa 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
@@ -158,9 +158,9 @@ namespace osu.Desktop.VisualTests.Tests
                 base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes);
 
                 timingPointCount.Value = timingPoints.Count;
-                currentTimingPoint.Value = timingPoints.IndexOf(timingPoint) + 1;
+                currentTimingPoint.Value = timingPoints.IndexOf(timingPoint);
                 beatCount.Value = calculateBeatCount(timingPoint);
-                currentBeat.Value = beatIndex + 1;
+                currentBeat.Value = beatIndex;
                 beatsPerMinute.Value = 60000 / timingPoint.BeatLength;
                 adjustedBeatLength.Value = timingPoint.BeatLength;
 

From fec6f2ba651276cfaffe14c064694be4304179b7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thomas=20M=C3=BCller?= <thomas94@gmx.net>
Date: Sun, 9 Jul 2017 19:47:54 +0300
Subject: [PATCH 19/41] Remove unnecessary usings

---
 osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs | 2 --
 1 file changed, 2 deletions(-)

diff --git a/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs b/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
index 95e24dd6fa..067bf47521 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
@@ -14,8 +14,6 @@ using OpenTK.Graphics;
 using osu.Game.Graphics.Sprites;
 using osu.Framework.Lists;
 using System;
-using System.Globalization;
-using osu.Framework.Allocation;
 using osu.Framework.Extensions.Color4Extensions;
 
 namespace osu.Desktop.VisualTests.Tests

From 15fe01d5ee403cbba70a52c6314ce37e012066af Mon Sep 17 00:00:00 2001
From: Dean Herbert <pe@ppy.sh>
Date: Mon, 10 Jul 2017 03:20:05 +0900
Subject: [PATCH 20/41] Update framework

---
 osu-framework | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/osu-framework b/osu-framework
index 8dc785a0ae..ea243f1fef 160000
--- a/osu-framework
+++ b/osu-framework
@@ -1 +1 @@
-Subproject commit 8dc785a0aecfb6df53496eff5bd9f961ff8deee6
+Subproject commit ea243f1fef4db2aa044c0d3fc980879dde383a24

From 7952e7caa9d83a8af27ac129a96361745afff08d Mon Sep 17 00:00:00 2001
From: Dean Herbert <pe@ppy.sh>
Date: Mon, 10 Jul 2017 03:22:08 +0900
Subject: [PATCH 21/41] Fix typos

---
 osu.Desktop.VisualTests/Tests/TestCaseContextMenu.cs            | 2 +-
 osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBouncer.cs | 2 +-
 osu.Game/Graphics/UserInterface/LoadingAnimation.cs             | 2 +-
 osu.Game/Overlays/Notifications/Notification.cs                 | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/osu.Desktop.VisualTests/Tests/TestCaseContextMenu.cs b/osu.Desktop.VisualTests/Tests/TestCaseContextMenu.cs
index c46aacc91a..c76a11035e 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseContextMenu.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseContextMenu.cs
@@ -60,7 +60,7 @@ namespace osu.Desktop.VisualTests.Tests
         {
             base.LoadComplete();
 
-            using (container.BeginLoopedSequece())
+            using (container.BeginLoopedSequence())
             {
                 container.MoveTo(new Vector2(0, 100), duration);
                 using (container.BeginDelayedSequence(duration))
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBouncer.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBouncer.cs
index 12d8193641..a34ff30a43 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBouncer.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBouncer.cs
@@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
         protected override void LoadComplete()
         {
             base.LoadComplete();
-            using (icon.BeginLoopedSequece())
+            using (icon.BeginLoopedSequence())
                 icon.RotateTo(360, 1000);
         }
 
diff --git a/osu.Game/Graphics/UserInterface/LoadingAnimation.cs b/osu.Game/Graphics/UserInterface/LoadingAnimation.cs
index 59e08ba004..eed5061abd 100644
--- a/osu.Game/Graphics/UserInterface/LoadingAnimation.cs
+++ b/osu.Game/Graphics/UserInterface/LoadingAnimation.cs
@@ -34,7 +34,7 @@ namespace osu.Game.Graphics.UserInterface
         {
             base.LoadComplete();
 
-            using (spinner.BeginLoopedSequece())
+            using (spinner.BeginLoopedSequence())
                 spinner.RotateTo(360, 2000);
         }
 
diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs
index 2a9297c443..4d29361cff 100644
--- a/osu.Game/Overlays/Notifications/Notification.cs
+++ b/osu.Game/Overlays/Notifications/Notification.cs
@@ -213,7 +213,7 @@ namespace osu.Game.Overlays.Notifications
                     if (pulsate)
                     {
                         const float length = 1000;
-                        using (pulsateLayer.BeginLoopedSequece(length / 2))
+                        using (pulsateLayer.BeginLoopedSequence(length / 2))
                         {
                             pulsateLayer.FadeTo(0.4f, length, EasingTypes.In);
                             using (pulsateLayer.BeginDelayedSequence(length))

From f856e89b58a419896f5911ac700fa6dc541982e6 Mon Sep 17 00:00:00 2001
From: Dean Herbert <pe@ppy.sh>
Date: Mon, 10 Jul 2017 03:37:51 +0900
Subject: [PATCH 22/41] Fix CI issues

---
 osu.Desktop.VisualTests/Tests/TestCaseContextMenu.cs | 3 +--
 osu.Game/Overlays/Notifications/Notification.cs      | 1 -
 2 files changed, 1 insertion(+), 3 deletions(-)

diff --git a/osu.Desktop.VisualTests/Tests/TestCaseContextMenu.cs b/osu.Desktop.VisualTests/Tests/TestCaseContextMenu.cs
index c76a11035e..f9dc424153 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseContextMenu.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseContextMenu.cs
@@ -7,7 +7,6 @@ using osu.Framework.Graphics;
 using osu.Framework.Graphics.Containers;
 using osu.Framework.Graphics.Cursor;
 using osu.Framework.Graphics.Shapes;
-using osu.Framework.Graphics.Transforms;
 using osu.Framework.Graphics.UserInterface;
 using osu.Framework.Testing;
 using osu.Game.Graphics.UserInterface;
@@ -21,7 +20,7 @@ namespace osu.Desktop.VisualTests.Tests
         private const int start_time = 0;
         private const int duration = 1000;
 
-        private Container container;
+        private readonly Container container;
 
         public TestCaseContextMenu()
         {
diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs
index 4d29361cff..74cced5ee9 100644
--- a/osu.Game/Overlays/Notifications/Notification.cs
+++ b/osu.Game/Overlays/Notifications/Notification.cs
@@ -7,7 +7,6 @@ using osu.Framework.Extensions.Color4Extensions;
 using osu.Framework.Graphics;
 using osu.Framework.Graphics.Colour;
 using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Transforms;
 using osu.Framework.Input;
 using osu.Game.Graphics;
 using OpenTK;

From 0e2dc9388af40be45090322c8f36a87a482a12b6 Mon Sep 17 00:00:00 2001
From: Dean Herbert <pe@ppy.sh>
Date: Mon, 10 Jul 2017 07:01:25 +0900
Subject: [PATCH 23/41] More changes in-line with framework changes.

---
 .../Tests/TestCaseHitObjects.cs               |  6 +--
 .../Objects/Drawable/DrawableFruit.cs         |  7 +--
 osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs  | 13 ++---
 .../Objects/Drawables/DrawableHitCircle.cs    | 50 +++++++++++--------
 .../Objects/Drawables/DrawableOsuHitObject.cs | 11 ++--
 osu.Game/Graphics/IHasAccentColour.cs         |  2 +-
 .../Graphics/Transforms/TransformAccent.cs    | 12 ++---
 .../UserInterface/PercentageCounter.cs        |  9 ++--
 .../Graphics/UserInterface/RollingCounter.cs  |  1 -
 .../Graphics/UserInterface/ScoreCounter.cs    |  9 ++--
 .../UserInterface/SimpleComboCounter.cs       |  9 ++--
 osu.Game/Overlays/DragBar.cs                  |  9 ++--
 osu.Game/Screens/Play/HUD/ComboCounter.cs     | 10 ++--
 .../Screens/Play/HUD/ComboResultCounter.cs    |  9 ++--
 .../Tournament/ScrollingTeamContainer.cs      |  9 ++--
 15 files changed, 68 insertions(+), 98 deletions(-)

diff --git a/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs b/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs
index 33841cae90..62b5ba5a68 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs
@@ -34,9 +34,9 @@ namespace osu.Desktop.VisualTests.Tests
 
             AddStep(@"circles", () => loadHitobjects(HitObjectType.Circle));
             AddStep(@"slider", () => loadHitobjects(HitObjectType.Slider));
-            AddStep(@"spinner", () => loadHitobjects(HitObjectType.Spinner));
+            //AddStep(@"spinner", () => loadHitobjects(HitObjectType.Spinner));
 
-            AddToggleStep(@"auto", state => { auto = state; loadHitobjects(mode); });
+            //AddToggleStep(@"auto", state => { auto = state; loadHitobjects(mode); });
 
             BasicSliderBar<double> sliderBar;
             Add(new Container
@@ -87,7 +87,7 @@ namespace osu.Desktop.VisualTests.Tests
             switch (mode)
             {
                 case HitObjectType.Circle:
-                    const int count = 10;
+                    const int count = 1;
 
                     for (int i = 0; i < count; i++)
                     {
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs
index ae6585bdb2..432d0e6256 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs
@@ -5,7 +5,6 @@ using osu.Framework.Allocation;
 using osu.Framework.Graphics;
 using osu.Framework.Graphics.Sprites;
 using osu.Framework.Graphics.Textures;
-using osu.Framework.Graphics.Transforms;
 using OpenTK;
 
 namespace osu.Game.Rulesets.Catch.Objects.Drawable
@@ -29,10 +28,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
         {
             Texture = textures.Get(@"Menu/logo");
 
-            const double duration = 0;
-
-            Transforms.Add(new TransformPosition { StartTime = h.StartTime - 200, EndTime = h.StartTime, StartValue = new Vector2(h.Position, -0.1f), EndValue = new Vector2(h.Position, 0.9f) });
-            Transforms.Add(new TransformAlpha { StartTime = h.StartTime + duration + 200, EndTime = h.StartTime + duration + 400, StartValue = 1, EndValue = 0 });
+            //Transforms.Add(new TransformPosition { StartTime = h.StartTime - 200, EndTime = h.StartTime, StartValue = new Vector2(h.Position, -0.1f), EndValue = new Vector2(h.Position, 0.9f) });
+            //Transforms.Add(new TransformAlpha { StartTime = h.StartTime + duration + 200, EndTime = h.StartTime + duration + 400, StartValue = 1, EndValue = 0 });
             Expire(true);
         }
     }
diff --git a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs
index a0c683143c..af875a2e52 100644
--- a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs
+++ b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs
@@ -235,7 +235,7 @@ namespace osu.Game.Rulesets.Mania.UI
 
         private void transformVisibleTimeRangeTo(double newTimeRange, double duration = 0, EasingTypes easing = EasingTypes.None)
         {
-            TransformTo(() => visibleTimeRange.Value, newTimeRange, duration, easing, new TransformTimeSpan());
+            TransformTo(newTimeRange, duration, easing, new TransformTimeSpan());
         }
 
         protected override void Update()
@@ -247,7 +247,7 @@ namespace osu.Game.Rulesets.Mania.UI
 
         private class TransformTimeSpan : Transform<double, Drawable>
         {
-            public override double CurrentValue
+            public virtual double CurrentValue
             {
                 get
                 {
@@ -259,13 +259,8 @@ namespace osu.Game.Rulesets.Mania.UI
                 }
             }
 
-            public override void Apply(Drawable d)
-            {
-                base.Apply(d);
-
-                var p = (ManiaPlayfield)d;
-                p.visibleTimeRange.Value = (float)CurrentValue;
-            }
+            public override void Apply(Drawable d) => ((ManiaPlayfield)d).visibleTimeRange.Value = (float)CurrentValue;
+            public override void ReadIntoStartValue(Drawable d) => StartValue = ((ManiaPlayfield)d).visibleTimeRange.Value;
         }
     }
 }
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs
index 09bfffeefe..75b2dc0a32 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs
@@ -89,11 +89,15 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
         {
             base.UpdateInitialState();
 
-            //sane defaults
-            ring.Alpha = circle.Alpha = number.Alpha = glow.Alpha = 1;
-            ApproachCircle.Alpha = 0;
-            ApproachCircle.Scale = new Vector2(4);
-            explode.Alpha = 0;
+            // sane defaults
+            ring.Show();
+            circle.Show();
+            number.Show();
+            glow.Show();
+
+            ApproachCircle.Hide();
+            ApproachCircle.ScaleTo(new Vector2(4));
+            explode.Hide();
         }
 
         protected override void UpdatePreemptState()
@@ -106,43 +110,45 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
 
         protected override void UpdateCurrentState(ArmedState state)
         {
-            ApproachCircle.FadeOut();
+            double duration = ((HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime) - HitObject.StartTime;
 
-            double endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime;
-            double duration = endTime - HitObject.StartTime;
-
-            glow.Delay(duration);
-            glow.FadeOut(400);
+            using (glow.BeginDelayedSequence(duration))
+                glow.FadeOut(400);
 
             switch (state)
             {
                 case ArmedState.Idle:
-                    Delay(duration + TIME_PREEMPT);
-                    FadeOut(TIME_FADEOUT);
+                    using (BeginDelayedSequence(duration + TIME_PREEMPT))
+                        FadeOut(TIME_FADEOUT);
                     Expire(true);
                     break;
                 case ArmedState.Miss:
+                    ApproachCircle.FadeOut(50);
                     FadeOut(TIME_FADEOUT / 5);
                     Expire();
                     break;
                 case ArmedState.Hit:
+                    ApproachCircle.FadeOut(50);
+
                     const double flash_in = 40;
 
                     flash.FadeTo(0.8f, flash_in);
-                    flash.Delay(flash_in);
-                    flash.FadeOut(100);
+                    using (flash.BeginDelayedSequence(flash_in))
+                        flash.FadeOut(100);
 
                     explode.FadeIn(flash_in);
 
-                    Delay(flash_in, true);
+                    using (BeginDelayedSequence(flash_in, true))
+                    {
+                        //after the flash, we can hide some elements that were behind it
+                        ring.FadeOut();
+                        circle.FadeOut();
+                        number.FadeOut();
 
-                    //after the flash, we can hide some elements that were behind it
-                    ring.FadeOut();
-                    circle.FadeOut();
-                    number.FadeOut();
+                        FadeOut(800);
+                        ScaleTo(Scale * 1.5f, 400, EasingTypes.OutQuad);
+                    }
 
-                    FadeOut(800);
-                    ScaleTo(Scale * 1.5f, 400, EasingTypes.OutQuad);
                     Expire();
                     break;
             }
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs
index 57a9804330..2711ec1a62 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs
@@ -17,6 +17,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
             : base(hitObject)
         {
             AccentColour = HitObject.ComboColour;
+            Alpha = 0;
         }
 
         protected override OsuJudgement CreateJudgement() => new OsuJudgement { MaxScore = OsuScoreResult.Hit300 };
@@ -25,10 +26,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
         {
             Flush();
 
-            UpdateInitialState();
-
             using (BeginAbsoluteSequence(HitObject.StartTime - TIME_PREEMPT, true))
             {
+                UpdateInitialState();
+
                 UpdatePreemptState();
 
                 using (BeginDelayedSequence(TIME_PREEMPT + Judgement.TimeOffset, true))
@@ -36,8 +37,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
             }
         }
 
-        protected virtual void UpdateCurrentState(ArmedState state)
+        protected virtual void UpdateInitialState()
         {
+            Hide();
         }
 
         protected virtual void UpdatePreemptState()
@@ -45,9 +47,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
             FadeIn(TIME_FADEIN);
         }
 
-        protected virtual void UpdateInitialState()
+        protected virtual void UpdateCurrentState(ArmedState state)
         {
-            Alpha = 0;
         }
     }
 
diff --git a/osu.Game/Graphics/IHasAccentColour.cs b/osu.Game/Graphics/IHasAccentColour.cs
index 672c59a935..9eb66d8fac 100644
--- a/osu.Game/Graphics/IHasAccentColour.cs
+++ b/osu.Game/Graphics/IHasAccentColour.cs
@@ -30,7 +30,7 @@ namespace osu.Game.Graphics
         public static void FadeAccent<T>(this T accentedDrawable, Color4 newColour, double duration = 0, EasingTypes easing = EasingTypes.None)
             where T : Transformable<Drawable>, IHasAccentColour
         {
-            accentedDrawable.TransformTo(() => accentedDrawable.AccentColour, newColour, duration, easing, new TransformAccent());
+            accentedDrawable.TransformTo(newColour, duration, easing, new TransformAccent());
         }
     }
 }
diff --git a/osu.Game/Graphics/Transforms/TransformAccent.cs b/osu.Game/Graphics/Transforms/TransformAccent.cs
index d49f969c20..53a452ad8a 100644
--- a/osu.Game/Graphics/Transforms/TransformAccent.cs
+++ b/osu.Game/Graphics/Transforms/TransformAccent.cs
@@ -13,7 +13,7 @@ namespace osu.Game.Graphics.Transforms
         /// <summary>
         /// Current value of the transformed colour in linear colour space.
         /// </summary>
-        public override Color4 CurrentValue
+        public virtual Color4 CurrentValue
         {
             get
             {
@@ -25,13 +25,7 @@ namespace osu.Game.Graphics.Transforms
             }
         }
 
-        public override void Apply(Drawable d)
-        {
-            base.Apply(d);
-
-            var accented = d as IHasAccentColour;
-            if (accented != null)
-                accented.AccentColour = CurrentValue;
-        }
+        public override void Apply(Drawable d) => ((IHasAccentColour)d).AccentColour = CurrentValue;
+        public override void ReadIntoStartValue(Drawable d) => StartValue = ((IHasAccentColour)d).AccentColour;
     }
 }
diff --git a/osu.Game/Graphics/UserInterface/PercentageCounter.cs b/osu.Game/Graphics/UserInterface/PercentageCounter.cs
index 79cdc9effe..b51dd2287b 100644
--- a/osu.Game/Graphics/UserInterface/PercentageCounter.cs
+++ b/osu.Game/Graphics/UserInterface/PercentageCounter.cs
@@ -47,7 +47,7 @@ namespace osu.Game.Graphics.UserInterface
 
         protected class TransformAccuracy : Transform<double, Drawable>
         {
-            public override double CurrentValue
+            public virtual double CurrentValue
             {
                 get
                 {
@@ -59,11 +59,8 @@ namespace osu.Game.Graphics.UserInterface
                 }
             }
 
-            public override void Apply(Drawable d)
-            {
-                base.Apply(d);
-                ((PercentageCounter)d).DisplayedCount = CurrentValue;
-            }
+            public override void Apply(Drawable d) => ((PercentageCounter)d).DisplayedCount = CurrentValue;
+            public override void ReadIntoStartValue(Drawable d) => StartValue = ((PercentageCounter)d).DisplayedCount;
         }
     }
 }
diff --git a/osu.Game/Graphics/UserInterface/RollingCounter.cs b/osu.Game/Graphics/UserInterface/RollingCounter.cs
index 4338dd23eb..db6e6ff44f 100644
--- a/osu.Game/Graphics/UserInterface/RollingCounter.cs
+++ b/osu.Game/Graphics/UserInterface/RollingCounter.cs
@@ -210,7 +210,6 @@ namespace osu.Game.Graphics.UserInterface
 
             transform.StartTime = TransformStartTime;
             transform.EndTime = TransformStartTime + rollingTotalDuration;
-            transform.StartValue = currentValue;
             transform.EndValue = newValue;
             transform.Easing = RollingEasing;
 
diff --git a/osu.Game/Graphics/UserInterface/ScoreCounter.cs b/osu.Game/Graphics/UserInterface/ScoreCounter.cs
index f98e84852a..6fe43e1fcc 100644
--- a/osu.Game/Graphics/UserInterface/ScoreCounter.cs
+++ b/osu.Game/Graphics/UserInterface/ScoreCounter.cs
@@ -58,7 +58,7 @@ namespace osu.Game.Graphics.UserInterface
 
         protected class TransformScore : Transform<double, Drawable>
         {
-            public override double CurrentValue
+            public virtual double CurrentValue
             {
                 get
                 {
@@ -70,11 +70,8 @@ namespace osu.Game.Graphics.UserInterface
                 }
             }
 
-            public override void Apply(Drawable d)
-            {
-                base.Apply(d);
-                ((ScoreCounter)d).DisplayedCount = CurrentValue;
-            }
+            public override void Apply(Drawable d) => ((ScoreCounter)d).DisplayedCount = CurrentValue;
+            public override void ReadIntoStartValue(Drawable d) => StartValue = ((ScoreCounter)d).DisplayedCount;
         }
     }
 }
diff --git a/osu.Game/Graphics/UserInterface/SimpleComboCounter.cs b/osu.Game/Graphics/UserInterface/SimpleComboCounter.cs
index bee1a71894..a512728cea 100644
--- a/osu.Game/Graphics/UserInterface/SimpleComboCounter.cs
+++ b/osu.Game/Graphics/UserInterface/SimpleComboCounter.cs
@@ -39,7 +39,7 @@ namespace osu.Game.Graphics.UserInterface
 
         private class TransformCounterCount : Transform<int, Drawable>
         {
-            public override int CurrentValue
+            public virtual int CurrentValue
             {
                 get
                 {
@@ -51,11 +51,8 @@ namespace osu.Game.Graphics.UserInterface
                 }
             }
 
-            public override void Apply(Drawable d)
-            {
-                base.Apply(d);
-                ((SimpleComboCounter)d).DisplayedCount = CurrentValue;
-            }
+            public override void Apply(Drawable d) => ((SimpleComboCounter)d).DisplayedCount = CurrentValue;
+            public override void ReadIntoStartValue(Drawable d) => StartValue = ((SimpleComboCounter)d).DisplayedCount;
         }
     }
 }
\ No newline at end of file
diff --git a/osu.Game/Overlays/DragBar.cs b/osu.Game/Overlays/DragBar.cs
index 07e0c76396..89bb81c70b 100644
--- a/osu.Game/Overlays/DragBar.cs
+++ b/osu.Game/Overlays/DragBar.cs
@@ -75,7 +75,7 @@ namespace osu.Game.Overlays
         private void updatePosition(float position, bool easing = true)
         {
             position = MathHelper.Clamp(position, 0, 1);
-            Fill.TransformTo(() => Fill.Width, position, easing ? 200 : 0, EasingTypes.OutQuint, new TransformSeek());
+            Fill.TransformTo(position, easing ? 200 : 0, EasingTypes.OutQuint, new TransformSeek());
         }
 
         protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
@@ -100,11 +100,8 @@ namespace osu.Game.Overlays
 
         private class TransformSeek : TransformFloat<Drawable>
         {
-            public override void Apply(Drawable d)
-            {
-                base.Apply(d);
-                d.Width = CurrentValue;
-            }
+            public override void Apply(Drawable d) => d.Width = CurrentValue;
+            public override void ReadIntoStartValue(Drawable d) => StartValue = d.Width;
         }
     }
 }
diff --git a/osu.Game/Screens/Play/HUD/ComboCounter.cs b/osu.Game/Screens/Play/HUD/ComboCounter.cs
index 3793181ecd..f527eaacaf 100644
--- a/osu.Game/Screens/Play/HUD/ComboCounter.cs
+++ b/osu.Game/Screens/Play/HUD/ComboCounter.cs
@@ -198,7 +198,6 @@ namespace osu.Game.Screens.Play.HUD
 
             transform.StartTime = Time.Current;
             transform.EndTime = Time.Current + getProportionalDuration(currentValue, newValue);
-            transform.StartValue = currentValue;
             transform.EndValue = newValue;
             transform.Easing = RollingEasing;
 
@@ -207,7 +206,7 @@ namespace osu.Game.Screens.Play.HUD
 
         protected class TransformComboRoll : Transform<int, Drawable>
         {
-            public override int CurrentValue
+            public virtual int CurrentValue
             {
                 get
                 {
@@ -219,11 +218,8 @@ namespace osu.Game.Screens.Play.HUD
                 }
             }
 
-            public override void Apply(Drawable d)
-            {
-                base.Apply(d);
-                ((ComboCounter)d).DisplayedCount = CurrentValue;
-            }
+            public override void Apply(Drawable d) => ((ComboCounter)d).DisplayedCount = CurrentValue;
+            public override void ReadIntoStartValue(Drawable d) => StartValue = ((ComboCounter)d).DisplayedCount;
         }
 
         protected abstract void OnDisplayedCountRolling(int currentValue, int newValue);
diff --git a/osu.Game/Screens/Play/HUD/ComboResultCounter.cs b/osu.Game/Screens/Play/HUD/ComboResultCounter.cs
index a4a20c1fd0..c280702390 100644
--- a/osu.Game/Screens/Play/HUD/ComboResultCounter.cs
+++ b/osu.Game/Screens/Play/HUD/ComboResultCounter.cs
@@ -36,7 +36,7 @@ namespace osu.Game.Screens.Play.HUD
 
         protected class TransformComboResult : Transform<ulong, Drawable>
         {
-            public override ulong CurrentValue
+            public virtual ulong CurrentValue
             {
                 get
                 {
@@ -48,11 +48,8 @@ namespace osu.Game.Screens.Play.HUD
                 }
             }
 
-            public override void Apply(Drawable d)
-            {
-                base.Apply(d);
-                ((ComboResultCounter)d).DisplayedCount = CurrentValue;
-            }
+            public override void Apply(Drawable d) => ((ComboResultCounter)d).DisplayedCount = CurrentValue;
+            public override void ReadIntoStartValue(Drawable d) => StartValue = ((ComboResultCounter)d).DisplayedCount;
         }
     }
 }
diff --git a/osu.Game/Screens/Tournament/ScrollingTeamContainer.cs b/osu.Game/Screens/Tournament/ScrollingTeamContainer.cs
index a7019f1e35..30f109e598 100644
--- a/osu.Game/Screens/Tournament/ScrollingTeamContainer.cs
+++ b/osu.Game/Screens/Tournament/ScrollingTeamContainer.cs
@@ -297,7 +297,7 @@ namespace osu.Game.Screens.Tournament
             }
         }
 
-        private void speedTo(float value, double duration = 0, EasingTypes easing = EasingTypes.None) => TransformTo(() => speed, value, duration, easing, new TransformScrollSpeed());
+        private void speedTo(float value, double duration = 0, EasingTypes easing = EasingTypes.None) => TransformTo(value, duration, easing, new TransformScrollSpeed());
 
         private enum ScrollState
         {
@@ -310,11 +310,8 @@ namespace osu.Game.Screens.Tournament
 
         public class TransformScrollSpeed : TransformFloat<Drawable>
         {
-            public override void Apply(Drawable d)
-            {
-                base.Apply(d);
-                ((ScrollingTeamContainer)d).speed = CurrentValue;
-            }
+            public override void Apply(Drawable d) => ((ScrollingTeamContainer)d).speed = CurrentValue;
+            public override void ReadIntoStartValue(Drawable d) => StartValue = ((ScrollingTeamContainer)d).speed;
         }
 
         public class ScrollingTeam : Container

From 0e0c32008b938dae94760a77075d8dfe68271fe3 Mon Sep 17 00:00:00 2001
From: Dean Herbert <pe@ppy.sh>
Date: Mon, 10 Jul 2017 15:40:40 +0900
Subject: [PATCH 24/41] More changes

---
 osu.Game/Screens/Play/PlayerInputManager.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/osu.Game/Screens/Play/PlayerInputManager.cs b/osu.Game/Screens/Play/PlayerInputManager.cs
index f5e57f9e9d..b112a02113 100644
--- a/osu.Game/Screens/Play/PlayerInputManager.cs
+++ b/osu.Game/Screens/Play/PlayerInputManager.cs
@@ -75,7 +75,7 @@ namespace osu.Game.Screens.Play
 
         private const int max_catch_up_updates_per_frame = 50;
 
-        public override bool UpdateSubTree()
+        protected override bool UpdateSubTree()
         {
             requireMoreUpdateLoops = true;
             validState = true;

From c4e378571b40e2231cae70140dacb2a533ae8c94 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thomas=20M=C3=BCller?= <thomas94@gmx.net>
Date: Mon, 10 Jul 2017 11:54:23 +0300
Subject: [PATCH 25/41] Update framework

---
 osu-framework                               | 2 +-
 osu.Game/Screens/Play/PlayerInputManager.cs | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/osu-framework b/osu-framework
index ea243f1fef..870ae62a35 160000
--- a/osu-framework
+++ b/osu-framework
@@ -1 +1 @@
-Subproject commit ea243f1fef4db2aa044c0d3fc980879dde383a24
+Subproject commit 870ae62a35fc0296009bf6d711922da5b9b5612f
diff --git a/osu.Game/Screens/Play/PlayerInputManager.cs b/osu.Game/Screens/Play/PlayerInputManager.cs
index b112a02113..f5e57f9e9d 100644
--- a/osu.Game/Screens/Play/PlayerInputManager.cs
+++ b/osu.Game/Screens/Play/PlayerInputManager.cs
@@ -75,7 +75,7 @@ namespace osu.Game.Screens.Play
 
         private const int max_catch_up_updates_per_frame = 50;
 
-        protected override bool UpdateSubTree()
+        public override bool UpdateSubTree()
         {
             requireMoreUpdateLoops = true;
             validState = true;

From dfb484cfbbd1925b2ac8bbe2d8e033924430f7e1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thomas=20M=C3=BCller?= <thomas94@gmx.net>
Date: Mon, 10 Jul 2017 11:57:39 +0300
Subject: [PATCH 26/41] Restore altered test cases

---
 osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs         | 6 +++---
 .../Tests/TestCaseNotificationManager.cs                    | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs b/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs
index 62b5ba5a68..33841cae90 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs
@@ -34,9 +34,9 @@ namespace osu.Desktop.VisualTests.Tests
 
             AddStep(@"circles", () => loadHitobjects(HitObjectType.Circle));
             AddStep(@"slider", () => loadHitobjects(HitObjectType.Slider));
-            //AddStep(@"spinner", () => loadHitobjects(HitObjectType.Spinner));
+            AddStep(@"spinner", () => loadHitobjects(HitObjectType.Spinner));
 
-            //AddToggleStep(@"auto", state => { auto = state; loadHitobjects(mode); });
+            AddToggleStep(@"auto", state => { auto = state; loadHitobjects(mode); });
 
             BasicSliderBar<double> sliderBar;
             Add(new Container
@@ -87,7 +87,7 @@ namespace osu.Desktop.VisualTests.Tests
             switch (mode)
             {
                 case HitObjectType.Circle:
-                    const int count = 1;
+                    const int count = 10;
 
                     for (int i = 0; i < count; i++)
                     {
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseNotificationManager.cs b/osu.Desktop.VisualTests/Tests/TestCaseNotificationManager.cs
index bb2aa9ab0f..4ba50c8220 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseNotificationManager.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseNotificationManager.cs
@@ -34,7 +34,7 @@ namespace osu.Desktop.VisualTests.Tests
             AddStep(@"simple #2", sendNotification2);
             AddStep(@"progress #1", sendProgress1);
             AddStep(@"progress #2", sendProgress2);
-            //AddStep(@"barrage", () => sendBarrage());
+            AddStep(@"barrage", () => sendBarrage());
         }
 
         private void sendBarrage(int remaining = 100)

From d9b362489bbcbb253496c487c249fe0de4352235 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thomas=20M=C3=BCller?= <thomas94@gmx.net>
Date: Mon, 10 Jul 2017 12:07:38 +0300
Subject: [PATCH 27/41] Fix incorrect TimeUntilNextBeat and add
 TimeSinceLastBeat

---
 osu.Game/Graphics/Containers/BeatSyncedContainer.cs | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs
index 68b7637e10..5d8a5753b0 100644
--- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs
+++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs
@@ -28,6 +28,11 @@ namespace osu.Game.Graphics.Containers
         /// </summary>
         public double TimeUntilNextBeat { get; private set; }
 
+        /// <summary>
+        /// The time in milliseconds since the last beat
+        /// </summary>
+        public double TimeSinceLastBeat { get; private set; }
+
         protected override void Update()
         {
             if (Beatmap.Value?.Track == null)
@@ -48,11 +53,15 @@ namespace osu.Game.Graphics.Containers
                 beatIndex--;
 
             TimeUntilNextBeat = (timingPoint.Time - currentTrackTime) % timingPoint.BeatLength;
+            if (TimeUntilNextBeat < 0)
+                TimeUntilNextBeat += timingPoint.BeatLength;
+
+            TimeSinceLastBeat = timingPoint.BeatLength - TimeUntilNextBeat;
 
             if (timingPoint == lastTimingPoint && beatIndex == lastBeat)
                 return;
 
-            using (BeginDelayedSequence(TimeUntilNextBeat, true))
+            using (BeginDelayedSequence(-TimeSinceLastBeat, true))
                 OnNewBeat(beatIndex, timingPoint, effectPoint, Beatmap.Value.Track.CurrentAmplitudes);
 
             lastBeat = beatIndex;

From 77297600172474820955926ce3a5aeb67e8eff8c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thomas=20M=C3=BCller?= <thomas94@gmx.net>
Date: Mon, 10 Jul 2017 12:08:15 +0300
Subject: [PATCH 28/41] Add beat timings to TestCaseBeatSyncedContainer

---
 .../Tests/TestCaseBeatSyncedContainer.cs            | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs b/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
index 067bf47521..01d7d4ff01 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseBeatSyncedContainer.cs
@@ -58,6 +58,8 @@ namespace osu.Desktop.VisualTests.Tests
             private readonly InfoString currentBeat;
             private readonly InfoString beatsPerMinute;
             private readonly InfoString adjustedBeatLength;
+            private readonly InfoString timeUntilNextBeat;
+            private readonly InfoString timeSinceLastBeat;
 
             private readonly Box flashLayer;
 
@@ -95,6 +97,8 @@ namespace osu.Desktop.VisualTests.Tests
                                     currentBeat = new InfoString(@"Current beat"),
                                     beatsPerMinute = new InfoString(@"BPM"),
                                     adjustedBeatLength = new InfoString(@"Adjusted beat length"),
+                                    timeUntilNextBeat = new InfoString(@"Time until next beat"),
+                                    timeSinceLastBeat = new InfoString(@"Time since last beat"),
                                 }
                             }
                         }
@@ -131,6 +135,8 @@ namespace osu.Desktop.VisualTests.Tests
                     currentBeat.Value = 0;
                     beatsPerMinute.Value = 0;
                     adjustedBeatLength.Value = 0;
+                    timeUntilNextBeat.Value = 0;
+                    timeSinceLastBeat.Value = 0;
                 };
             }
 
@@ -151,6 +157,13 @@ namespace osu.Desktop.VisualTests.Tests
                 return (int)Math.Ceiling((getNextTimingPoint(current).Time - current.Time) / current.BeatLength);
             }
 
+            protected override void Update()
+            {
+                base.Update();
+                timeUntilNextBeat.Value = TimeUntilNextBeat;
+                timeSinceLastBeat.Value = TimeSinceLastBeat;
+            }
+
             protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes)
             {
                 base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes);

From e8ce3e16b0c749045f8357214fbade5d0c621ada Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thomas=20M=C3=BCller?= <thomas94@gmx.net>
Date: Mon, 10 Jul 2017 12:31:41 +0300
Subject: [PATCH 29/41] Address CI concern

---
 osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs | 4 ++--
 osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs              | 2 +-
 osu.Game/Graphics/UserInterface/SimpleComboCounter.cs     | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs
index 432d0e6256..3e7d9bd6d7 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs
@@ -11,11 +11,11 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
 {
     internal class DrawableFruit : Sprite
     {
-        private readonly CatchBaseHit h;
+        //private readonly CatchBaseHit h;
 
         public DrawableFruit(CatchBaseHit h)
         {
-            this.h = h;
+            //this.h = h;
 
             Origin = Anchor.Centre;
             Scale = new Vector2(0.1f);
diff --git a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs
index af875a2e52..3feb448752 100644
--- a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs
+++ b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs
@@ -247,7 +247,7 @@ namespace osu.Game.Rulesets.Mania.UI
 
         private class TransformTimeSpan : Transform<double, Drawable>
         {
-            public virtual double CurrentValue
+            public double CurrentValue
             {
                 get
                 {
diff --git a/osu.Game/Graphics/UserInterface/SimpleComboCounter.cs b/osu.Game/Graphics/UserInterface/SimpleComboCounter.cs
index a512728cea..7664eeee40 100644
--- a/osu.Game/Graphics/UserInterface/SimpleComboCounter.cs
+++ b/osu.Game/Graphics/UserInterface/SimpleComboCounter.cs
@@ -39,7 +39,7 @@ namespace osu.Game.Graphics.UserInterface
 
         private class TransformCounterCount : Transform<int, Drawable>
         {
-            public virtual int CurrentValue
+            public int CurrentValue
             {
                 get
                 {

From 4134f845591557e92c16cf3546169835756d7288 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thomas=20M=C3=BCller?= <thomas94@gmx.net>
Date: Mon, 10 Jul 2017 12:54:11 +0300
Subject: [PATCH 30/41] Increase test timeout to 1 minute

---
 osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
index 4a6b972f4a..910918297f 100644
--- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
+++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
@@ -111,7 +111,7 @@ namespace osu.Game.Tests.Beatmaps.IO
             return osu;
         }
 
-        private void ensureLoaded(GameHost host, int timeout = 10000)
+        private void ensureLoaded(GameHost host, int timeout = 60000)
         {
             IEnumerable<BeatmapSetInfo> resultSets = null;
 

From d6d79432c92a1fd18ed24bdec6661920b6ec903d Mon Sep 17 00:00:00 2001
From: Dean Herbert <pe@ppy.sh>
Date: Tue, 11 Jul 2017 09:59:08 +0900
Subject: [PATCH 31/41] Update framework

---
 osu-framework                        | 2 +-
 osu.Game/Overlays/OnScreenDisplay.cs | 2 --
 2 files changed, 1 insertion(+), 3 deletions(-)

diff --git a/osu-framework b/osu-framework
index 870ae62a35..768a775b68 160000
--- a/osu-framework
+++ b/osu-framework
@@ -1 +1 @@
-Subproject commit 870ae62a35fc0296009bf6d711922da5b9b5612f
+Subproject commit 768a775b688d7a008d8933275b48ed0d2d491f12
diff --git a/osu.Game/Overlays/OnScreenDisplay.cs b/osu.Game/Overlays/OnScreenDisplay.cs
index 4a616a8685..464c9893d1 100644
--- a/osu.Game/Overlays/OnScreenDisplay.cs
+++ b/osu.Game/Overlays/OnScreenDisplay.cs
@@ -260,8 +260,6 @@ namespace osu.Game.Overlays
                     Radius = 8,
                 };
 
-                FadeEdgeEffectTo(0);
-
                 updateGlow();
                 Flush(true);
             }

From e9b397f06fb397bde9039451c865fbb0db786c89 Mon Sep 17 00:00:00 2001
From: Dean Herbert <pe@ppy.sh>
Date: Tue, 11 Jul 2017 10:41:18 +0900
Subject: [PATCH 32/41] Remove assert which is not always true on some
 operating systems

---
 osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
index 910918297f..239c9f59e3 100644
--- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
+++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
@@ -75,18 +75,16 @@ namespace osu.Game.Tests.Beatmaps.IO
 
                 var temp = prepareTempCopy(osz_path);
 
-                Assert.IsTrue(File.Exists(temp));
+                Assert.IsTrue(File.Exists(temp), "Temporary file copy never substantiated");
 
                 using (File.OpenRead(temp))
                     host.Dependencies.Get<BeatmapDatabase>().Import(temp);
 
                 ensureLoaded(host);
 
-                Assert.IsTrue(File.Exists(temp));
-
                 File.Delete(temp);
 
-                Assert.IsFalse(File.Exists(temp));
+                Assert.IsFalse(File.Exists(temp), "We likely help a read lock not he file when we shouldn't");
             }
         }
 

From 327327ea92a6a0cb574186eb1264ae03953f8a30 Mon Sep 17 00:00:00 2001
From: Dean Herbert <pe@ppy.sh>
Date: Tue, 11 Jul 2017 10:43:43 +0900
Subject: [PATCH 33/41] Remove custom windows configuration from tasks.json

No longer required as mono 5.0 upwards handles this gracefully (while not yet adding full parallel support).
---
 .vscode/tasks.json | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index f285ebde67..b0fd5fbb0d 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -9,15 +9,9 @@
     "showOutput": "silent",
     "args": [
         "/property:GenerateFullPaths=true",
-        "/property:DebugType=portable"
+        "/property:DebugType=portable",
+        "/m" //parallel compiling support.
     ],
-    "windows": {
-        "args": [
-            "/property:GenerateFullPaths=true",
-            "/property:DebugType=portable",
-            "/m" //parallel compiling support. doesn't work well with mono atm
-        ]
-    },
     "tasks": [
         {
             "taskName": "Build (Debug)",

From 55d999e4a1f440d391b23846070b151403191cce Mon Sep 17 00:00:00 2001
From: Dean Herbert <pe@ppy.sh>
Date: Tue, 11 Jul 2017 10:45:43 +0900
Subject: [PATCH 34/41] Fix comment

---
 osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
index 239c9f59e3..e467df0c53 100644
--- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
+++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
@@ -84,7 +84,7 @@ namespace osu.Game.Tests.Beatmaps.IO
 
                 File.Delete(temp);
 
-                Assert.IsFalse(File.Exists(temp), "We likely help a read lock not he file when we shouldn't");
+                Assert.IsFalse(File.Exists(temp), "We likely held a read lock on the file when we shouldn't");
             }
         }
 

From a9c50786b2dea64abe66c6640eb1678b04a09102 Mon Sep 17 00:00:00 2001
From: Dean Herbert <pe@ppy.sh>
Date: Tue, 11 Jul 2017 13:20:17 +0900
Subject: [PATCH 35/41] Fix osu! logo on main menu ending up in the wrong place

Also switch to using BeginDelayedSequence where possible.
---
 osu.Game/Screens/Menu/ButtonSystem.cs | 127 +++++++++++++-------------
 1 file changed, 64 insertions(+), 63 deletions(-)

diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs
index 9ba16ab1ca..fd87fd1b38 100644
--- a/osu.Game/Screens/Menu/ButtonSystem.cs
+++ b/osu.Game/Screens/Menu/ButtonSystem.cs
@@ -213,88 +213,89 @@ namespace osu.Game.Screens.Menu
                 backButton.ContractStyle = 0;
                 settingsButton.ContractStyle = 0;
 
-                switch (state)
+                bool fromInitial = lastState == MenuState.Initial;
+
+                if (state == MenuState.TopLevel)
+                    buttonArea.Flush(true);
+
+                using (buttonArea.BeginDelayedSequence(fromInitial ? 150 : 0, true))
                 {
-                    case MenuState.Exit:
-                    case MenuState.Initial:
-                        toolbar?.Hide();
+                    switch (state)
+                    {
+                        case MenuState.Exit:
+                        case MenuState.Initial:
+                            toolbar?.Hide();
 
-                        buttonAreaBackground.ScaleTo(Vector2.One, 500, EasingTypes.Out);
-                        buttonArea.FadeOut(300);
+                            buttonAreaBackground.ScaleTo(Vector2.One, 500, EasingTypes.Out);
+                            buttonArea.FadeOut(300);
 
-                        osuLogo.Delay(150);
-                        osuLogo.MoveTo(Vector2.Zero, 800, EasingTypes.OutExpo);
-                        osuLogo.ScaleTo(1, 800, EasingTypes.OutExpo);
+                            using (osuLogo.BeginDelayedSequence(150))
+                            {
+                                osuLogo.MoveTo(Vector2.Zero, 800, EasingTypes.OutExpo);
+                                osuLogo.ScaleTo(1, 800, EasingTypes.OutExpo);
+                            }
 
-                        foreach (Button b in buttonsTopLevel)
-                            b.State = ButtonState.Contracted;
+                            foreach (Button b in buttonsTopLevel)
+                                b.State = ButtonState.Contracted;
 
-                        foreach (Button b in buttonsPlay)
-                            b.State = ButtonState.Contracted;
+                            foreach (Button b in buttonsPlay)
+                                b.State = ButtonState.Contracted;
 
-                        if (state == MenuState.Exit)
-                        {
-                            osuLogo.RotateTo(20, EXIT_DELAY * 1.5f);
-                            osuLogo.FadeOut(EXIT_DELAY);
-                        }
-                        else if (lastState == MenuState.TopLevel)
-                            sampleBack?.Play();
-                        break;
-                    case MenuState.TopLevel:
-                        buttonArea.Flush(true);
+                            if (state == MenuState.Exit)
+                            {
+                                osuLogo.RotateTo(20, EXIT_DELAY * 1.5f);
+                                osuLogo.FadeOut(EXIT_DELAY);
+                            }
+                            else if (lastState == MenuState.TopLevel)
+                                sampleBack?.Play();
+                            break;
+                        case MenuState.TopLevel:
+                            buttonAreaBackground.ScaleTo(Vector2.One, 200, EasingTypes.Out);
 
-                        buttonAreaBackground.ScaleTo(Vector2.One, 200, EasingTypes.Out);
+                            osuLogo.ClearTransforms();
+                            osuLogo.MoveTo(buttonFlow.DrawPosition, 200, EasingTypes.In);
+                            osuLogo.ScaleTo(0.5f, 200, EasingTypes.In);
 
-                        osuLogo.MoveTo(buttonFlow.DrawPosition, 200, EasingTypes.In);
-                        osuLogo.ScaleTo(0.5f, 200, EasingTypes.In);
+                            buttonArea.FadeIn(300);
 
-                        buttonArea.FadeIn(300);
-
-                        if (lastState == MenuState.Initial)
-                        {
-                            buttonArea.Delay(150, true);
-
-                            if (osuLogo.Scale.X > 0.5f)
+                            if (fromInitial && osuLogo.Scale.X > 0.5f)
                                 using (osuLogo.BeginDelayedSequence(200, true))
                                     osuLogo.Impact();
-                        }
 
-                        Scheduler.AddDelayed(() => toolbar?.Show(), 150);
+                            Scheduler.AddDelayed(() => toolbar?.Show(), 150);
 
-                        foreach (Button b in buttonsTopLevel)
-                            b.State = ButtonState.Expanded;
+                            foreach (Button b in buttonsTopLevel)
+                                b.State = ButtonState.Expanded;
 
-                        foreach (Button b in buttonsPlay)
-                            b.State = ButtonState.Contracted;
-                        break;
-                    case MenuState.Play:
-                        foreach (Button b in buttonsTopLevel)
-                            b.State = ButtonState.Exploded;
+                            foreach (Button b in buttonsPlay)
+                                b.State = ButtonState.Contracted;
+                            break;
+                        case MenuState.Play:
+                            foreach (Button b in buttonsTopLevel)
+                                b.State = ButtonState.Exploded;
 
-                        foreach (Button b in buttonsPlay)
-                            b.State = ButtonState.Expanded;
-                        break;
-                    case MenuState.EnteringMode:
-                        buttonAreaBackground.ScaleTo(new Vector2(2, 0), 300, EasingTypes.InSine);
+                            foreach (Button b in buttonsPlay)
+                                b.State = ButtonState.Expanded;
+                            break;
+                        case MenuState.EnteringMode:
+                            buttonAreaBackground.ScaleTo(new Vector2(2, 0), 300, EasingTypes.InSine);
 
-                        buttonsTopLevel.ForEach(b => b.ContractStyle = 1);
-                        buttonsPlay.ForEach(b => b.ContractStyle = 1);
-                        backButton.ContractStyle = 1;
-                        settingsButton.ContractStyle = 1;
+                            buttonsTopLevel.ForEach(b => b.ContractStyle = 1);
+                            buttonsPlay.ForEach(b => b.ContractStyle = 1);
+                            backButton.ContractStyle = 1;
+                            settingsButton.ContractStyle = 1;
 
-                        foreach (Button b in buttonsTopLevel)
-                            b.State = ButtonState.Contracted;
+                            foreach (Button b in buttonsTopLevel)
+                                b.State = ButtonState.Contracted;
 
-                        foreach (Button b in buttonsPlay)
-                            b.State = ButtonState.Contracted;
-                        break;
+                            foreach (Button b in buttonsPlay)
+                                b.State = ButtonState.Contracted;
+                            break;
+                    }
+
+                    backButton.State = state == MenuState.Play ? ButtonState.Expanded : ButtonState.Contracted;
+                    settingsButton.State = state == MenuState.TopLevel ? ButtonState.Expanded : ButtonState.Contracted;
                 }
-
-                backButton.State = state == MenuState.Play ? ButtonState.Expanded : ButtonState.Contracted;
-                settingsButton.State = state == MenuState.TopLevel ? ButtonState.Expanded : ButtonState.Contracted;
-
-                if (lastState == MenuState.Initial)
-                    buttonArea.DelayReset();
             }
         }
 

From 896582fc06d32d82b0f6ef3219134b67430dd550 Mon Sep 17 00:00:00 2001
From: Dean Herbert <pe@ppy.sh>
Date: Tue, 11 Jul 2017 14:54:24 +0900
Subject: [PATCH 36/41] Update framework

---
 osu-framework | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/osu-framework b/osu-framework
index 870ae62a35..6f7528255c 160000
--- a/osu-framework
+++ b/osu-framework
@@ -1 +1 @@
-Subproject commit 870ae62a35fc0296009bf6d711922da5b9b5612f
+Subproject commit 6f7528255c5d6cde72f1e92de539983bc4bce502

From 4045083dcd9b836b31502c68ad39db4884336063 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thomas=20M=C3=BCller?= <thomas94@gmx.net>
Date: Tue, 11 Jul 2017 21:21:58 +0300
Subject: [PATCH 37/41] Update sorting comparers in line with framework changes

---
 osu-framework                                 |  2 +-
 .../ReverseDepthFillFlowContainer.cs          |  5 +-
 .../Objects/HitObjectStartTimeComparer.cs     | 55 -------------------
 .../Rulesets/Timing/DrawableTimingSection.cs  | 17 +++++-
 .../Timing/SpeedAdjustmentCollection.cs       | 37 +++++--------
 .../Screens/Menu/FlowContainerWithOrigin.cs   |  2 +-
 osu.Game/Screens/Play/HUD/ModDisplay.cs       |  2 +-
 .../Select/Options/BeatmapOptionsOverlay.cs   |  2 +-
 osu.Game/osu.Game.csproj                      |  1 -
 9 files changed, 37 insertions(+), 86 deletions(-)
 delete mode 100644 osu.Game/Rulesets/Objects/HitObjectStartTimeComparer.cs

diff --git a/osu-framework b/osu-framework
index 6f7528255c..40dc967472 160000
--- a/osu-framework
+++ b/osu-framework
@@ -1 +1 @@
-Subproject commit 6f7528255c5d6cde72f1e92de539983bc4bce502
+Subproject commit 40dc96747288fab4ae137e74b0af7452dc8be792
diff --git a/osu.Game/Graphics/Containers/ReverseDepthFillFlowContainer.cs b/osu.Game/Graphics/Containers/ReverseDepthFillFlowContainer.cs
index 0b38bf5fe0..781e149078 100644
--- a/osu.Game/Graphics/Containers/ReverseDepthFillFlowContainer.cs
+++ b/osu.Game/Graphics/Containers/ReverseDepthFillFlowContainer.cs
@@ -8,9 +8,10 @@ using osu.Framework.Graphics.Containers;
 
 namespace osu.Game.Graphics.Containers
 {
-    public class ReverseDepthFillFlowContainer<T> : FillFlowContainer<T> where T : Drawable
+    public class ReverseChildIDFillFlowContainer<T> : FillFlowContainer<T> where T : Drawable
     {
-        protected override IComparer<Drawable> DepthComparer => new ReverseCreationOrderDepthComparer();
+        protected override int Compare(Drawable x, Drawable y) => CompareReverseChildID(x, y);
+
         protected override IEnumerable<Drawable> FlowingChildren => base.FlowingChildren.Reverse();
     }
 }
diff --git a/osu.Game/Rulesets/Objects/HitObjectStartTimeComparer.cs b/osu.Game/Rulesets/Objects/HitObjectStartTimeComparer.cs
deleted file mode 100644
index b089856dcb..0000000000
--- a/osu.Game/Rulesets/Objects/HitObjectStartTimeComparer.cs
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Framework.Graphics;
-using osu.Game.Rulesets.Objects.Drawables;
-
-namespace osu.Game.Rulesets.Objects
-{
-    /// <summary>
-    /// Compares two hit objects by their start time, falling back to creation order if their start time is equal.
-    /// </summary>
-    public class HitObjectStartTimeComparer : Drawable.CreationOrderDepthComparer
-    {
-        public override int Compare(Drawable x, Drawable y)
-        {
-            var hitObjectX = x as DrawableHitObject;
-            var hitObjectY = y as DrawableHitObject;
-
-            // If either of the two drawables are not hit objects, fall back to the base comparer
-            if (hitObjectX?.HitObject == null || hitObjectY?.HitObject == null)
-                return base.Compare(x, y);
-
-            // Compare by start time
-            int i = hitObjectX.HitObject.StartTime.CompareTo(hitObjectY.HitObject.StartTime);
-            if (i != 0)
-                return i;
-
-            return base.Compare(x, y);
-        }
-    }
-
-    /// <summary>
-    /// Compares two hit objects by their start time, falling back to creation order if their start time is equal.
-    /// This will compare the two hit objects in reverse order.
-    /// </summary>
-    public class HitObjectReverseStartTimeComparer : Drawable.ReverseCreationOrderDepthComparer
-    {
-        public override int Compare(Drawable x, Drawable y)
-        {
-            var hitObjectX = x as DrawableHitObject;
-            var hitObjectY = y as DrawableHitObject;
-
-            // If either of the two drawables are not hit objects, fall back to the base comparer
-            if (hitObjectX?.HitObject == null || hitObjectY?.HitObject == null)
-                return base.Compare(x, y);
-
-            // Compare by start time
-            int i = hitObjectY.HitObject.StartTime.CompareTo(hitObjectX.HitObject.StartTime);
-            if (i != 0)
-                return i;
-
-            return base.Compare(x, y);
-        }
-    }
-}
\ No newline at end of file
diff --git a/osu.Game/Rulesets/Timing/DrawableTimingSection.cs b/osu.Game/Rulesets/Timing/DrawableTimingSection.cs
index 589ee9991d..74ff721d50 100644
--- a/osu.Game/Rulesets/Timing/DrawableTimingSection.cs
+++ b/osu.Game/Rulesets/Timing/DrawableTimingSection.cs
@@ -55,7 +55,22 @@ namespace osu.Game.Rulesets.Timing
         /// </summary>
         internal MultiplierControlPoint ControlPoint;
 
-        protected override IComparer<Drawable> DepthComparer => new HitObjectReverseStartTimeComparer();
+        protected override int Compare(Drawable x, Drawable y)
+        {
+            var xHitObject = x as DrawableHitObject;
+            var yHitObject = y as DrawableHitObject;
+
+            // If either of the two drawables are not hit objects, fall back to the base comparer
+            if (xHitObject?.HitObject == null || yHitObject?.HitObject == null)
+                return base.Compare(x, y);
+
+            // Compare by start time
+            int i = yHitObject.HitObject.StartTime.CompareTo(xHitObject.HitObject.StartTime);
+            if (i != 0)
+                return i;
+
+            return base.Compare(x, y);
+        }
 
         /// <summary>
         /// Creates a new <see cref="DrawableTimingSection"/>.
diff --git a/osu.Game/Rulesets/Timing/SpeedAdjustmentCollection.cs b/osu.Game/Rulesets/Timing/SpeedAdjustmentCollection.cs
index 1323bb14a1..22213be740 100644
--- a/osu.Game/Rulesets/Timing/SpeedAdjustmentCollection.cs
+++ b/osu.Game/Rulesets/Timing/SpeedAdjustmentCollection.cs
@@ -33,7 +33,20 @@ namespace osu.Game.Rulesets.Timing
             set { visibleTimeRange.BindTo(value); }
         }
 
-        protected override IComparer<Drawable> DepthComparer => new SpeedAdjustmentContainerReverseStartTimeComparer();
+        protected override int Compare(Drawable x, Drawable y)
+        {
+            var xSpeedAdjust = x as SpeedAdjustmentContainer;
+            var ySpeedAdjust = y as SpeedAdjustmentContainer;
+
+            // If either of the two drawables are not hit objects, fall back to the base comparer
+            if (xSpeedAdjust?.ControlPoint == null || ySpeedAdjust?.ControlPoint == null)
+                return CompareReverseChildID(x, y);
+
+            // Compare by start time
+            int i = ySpeedAdjust.ControlPoint.StartTime.CompareTo(xSpeedAdjust.ControlPoint.StartTime);
+
+            return i != 0 ? i : CompareReverseChildID(x, y);
+        }
 
         /// <summary>
         /// Hit objects that are to be re-processed on the next update.
@@ -116,27 +129,5 @@ namespace osu.Game.Rulesets.Timing
         /// <param name="time">The time to find the active <see cref="SpeedAdjustmentContainer"/> at.</param>
         /// <returns>The <see cref="SpeedAdjustmentContainer"/> active at <paramref name="time"/>. Null if there are no speed adjustments.</returns>
         private SpeedAdjustmentContainer adjustmentContainerAt(double time) => Children.FirstOrDefault(c => c.CanContain(time)) ?? Children.LastOrDefault();
-
-        /// <summary>
-        /// Compares two speed adjustment containers by their control point start time, falling back to creation order
-        // if their control point start time is equal. This will compare the two speed adjustment containers in reverse order.
-        /// </summary>
-        private class SpeedAdjustmentContainerReverseStartTimeComparer : ReverseCreationOrderDepthComparer
-        {
-            public override int Compare(Drawable x, Drawable y)
-            {
-                var speedAdjustmentX = x as SpeedAdjustmentContainer;
-                var speedAdjustmentY = y as SpeedAdjustmentContainer;
-
-                // If either of the two drawables are not hit objects, fall back to the base comparer
-                if (speedAdjustmentX?.ControlPoint == null || speedAdjustmentY?.ControlPoint == null)
-                    return base.Compare(x, y);
-
-                // Compare by start time
-                int i = speedAdjustmentY.ControlPoint.StartTime.CompareTo(speedAdjustmentX.ControlPoint.StartTime);
-
-                return i != 0 ? i : base.Compare(x, y);
-            }
-        }
     }
 }
diff --git a/osu.Game/Screens/Menu/FlowContainerWithOrigin.cs b/osu.Game/Screens/Menu/FlowContainerWithOrigin.cs
index d0972ea84b..071de99209 100644
--- a/osu.Game/Screens/Menu/FlowContainerWithOrigin.cs
+++ b/osu.Game/Screens/Menu/FlowContainerWithOrigin.cs
@@ -20,7 +20,7 @@ namespace osu.Game.Screens.Menu
         /// </summary>
         public Drawable CentreTarget;
 
-        protected override IComparer<Drawable> DepthComparer => new ReverseCreationOrderDepthComparer();
+        protected override int Compare(Drawable x, Drawable y) => CompareReverseChildID(x, y);
 
         protected override IEnumerable<Drawable> FlowingChildren => base.FlowingChildren.Reverse();
 
diff --git a/osu.Game/Screens/Play/HUD/ModDisplay.cs b/osu.Game/Screens/Play/HUD/ModDisplay.cs
index 921accf6ac..4cbea43ac5 100644
--- a/osu.Game/Screens/Play/HUD/ModDisplay.cs
+++ b/osu.Game/Screens/Play/HUD/ModDisplay.cs
@@ -27,7 +27,7 @@ namespace osu.Game.Screens.Play.HUD
         {
             Children = new Drawable[]
             {
-                iconsContainer = new ReverseDepthFillFlowContainer<ModIcon>
+                iconsContainer = new ReverseChildIDFillFlowContainer<ModIcon>
                 {
                     Anchor = Anchor.TopCentre,
                     Origin = Anchor.TopCentre,
diff --git a/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs b/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs
index f18080d6f5..6345807ea3 100644
--- a/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs
+++ b/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs
@@ -70,7 +70,7 @@ namespace osu.Game.Screens.Select.Options
                     Scale = new Vector2(1, 0),
                     Colour = Color4.Black.Opacity(0.5f),
                 },
-                buttonsContainer = new ReverseDepthFillFlowContainer<BeatmapOptionsButton>
+                buttonsContainer = new ReverseChildIDFillFlowContainer<BeatmapOptionsButton>
                 {
                     Height = height,
                     RelativePositionAxes = Axes.X,
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 06d4da663e..0b5bab2b45 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -190,7 +190,6 @@
     <Compile Include="Rulesets\Objects\Drawables\IScrollingHitObject.cs" />
     <Compile Include="Rulesets\Judgements\Judgement.cs" />
     <Compile Include="Rulesets\Objects\HitObjectParser.cs" />
-    <Compile Include="Rulesets\Objects\HitObjectStartTimeComparer.cs" />
     <Compile Include="Rulesets\Objects\Types\IHasCombo.cs" />
     <Compile Include="Rulesets\Objects\Types\IHasEndTime.cs" />
     <Compile Include="Rulesets\Objects\Types\IHasDistance.cs" />

From 9d523ea012625f98484bb61b2e4cd671b8ec1aca Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thomas=20M=C3=BCller?= <thomas94@gmx.net>
Date: Tue, 11 Jul 2017 16:58:06 +0300
Subject: [PATCH 38/41] Update framework

---
 osu-framework                                 |  2 +-
 .../Tests/TestCaseGamefield.cs                |  2 +-
 .../Tests/TestCaseScoreCounter.cs             | 12 +++++-----
 .../Tests/TestCaseScrollingHitObjects.cs      |  2 +-
 osu.Desktop/Overlays/VersionManager.cs        |  2 +-
 .../Objects/Drawables/DrawableHoldNote.cs     |  2 +-
 osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs      |  2 +-
 .../Objects/Drawables/Pieces/CirclePiece.cs   |  2 +-
 osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs  |  2 +-
 osu.Game/Beatmaps/Drawables/BeatmapPanel.cs   |  2 +-
 .../Graphics/Containers/SectionsContainer.cs  |  2 +-
 osu.Game/Graphics/UserInterface/BarGraph.cs   |  2 +-
 osu.Game/Graphics/UserInterface/OsuButton.cs  |  2 +-
 .../Graphics/UserInterface/SearchTextBox.cs   |  2 +-
 .../Graphics/UserInterface/StarCounter.cs     | 22 +++++++++----------
 osu.Game/OsuGame.cs                           |  2 +-
 osu.Game/Overlays/Chat/DrawableChannel.cs     |  2 +-
 osu.Game/Overlays/Mods/ModButton.cs           |  2 +-
 .../Overlays/Notifications/Notification.cs    |  2 +-
 .../Notifications/NotificationSection.cs      |  2 +-
 .../Notifications/SimpleNotification.cs       |  2 +-
 osu.Game/Overlays/Settings/SettingsSection.cs |  2 +-
 .../Overlays/Settings/SettingsSubsection.cs   |  2 +-
 osu.Game/Screens/Menu/ButtonSystem.cs         |  4 ++--
 osu.Game/Screens/Play/KeyCounter.cs           | 16 +++++++-------
 osu.Game/Screens/Play/Player.cs               |  2 +-
 osu.Game/Screens/Ranking/ResultsPage.cs       |  2 +-
 osu.Game/Screens/Select/BeatmapCarousel.cs    |  9 ++------
 osu.Game/Screens/Select/BeatmapDetailArea.cs  |  4 ++--
 29 files changed, 54 insertions(+), 59 deletions(-)

diff --git a/osu-framework b/osu-framework
index 6f7528255c..46a56e0e11 160000
--- a/osu-framework
+++ b/osu-framework
@@ -1 +1 @@
-Subproject commit 6f7528255c5d6cde72f1e92de539983bc4bce502
+Subproject commit 46a56e0e11d56c788ff8db089582718a606ed158
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseGamefield.cs b/osu.Desktop.VisualTests/Tests/TestCaseGamefield.cs
index 00d7e8b5c8..0c5f21a185 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseGamefield.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseGamefield.cs
@@ -76,7 +76,7 @@ namespace osu.Desktop.VisualTests.Tests
                 ControlPointInfo = controlPointInfo
             });
 
-            Add(new Drawable[]
+            AddRange(new Drawable[]
             {
                 new Container
                 {
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseScoreCounter.cs b/osu.Desktop.VisualTests/Tests/TestCaseScoreCounter.cs
index e8fc2956b4..fc29e8481e 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseScoreCounter.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseScoreCounter.cs
@@ -50,7 +50,7 @@ namespace osu.Desktop.VisualTests.Tests
                 Origin = Anchor.BottomLeft,
                 Anchor = Anchor.BottomLeft,
                 Position = new Vector2(20, -160),
-                Count = 5,
+                CountStars = 5,
             };
             Add(stars);
 
@@ -59,7 +59,7 @@ namespace osu.Desktop.VisualTests.Tests
                 Origin = Anchor.BottomLeft,
                 Anchor = Anchor.BottomLeft,
                 Position = new Vector2(20, -190),
-                Text = stars.Count.ToString("0.00"),
+                Text = stars.CountStars.ToString("0.00"),
             };
             Add(starsLabel);
 
@@ -69,8 +69,8 @@ namespace osu.Desktop.VisualTests.Tests
                 comboCounter.Current.Value = 0;
                 numerator = denominator = 0;
                 accuracyCounter.SetFraction(0, 0);
-                stars.Count = 0;
-                starsLabel.Text = stars.Count.ToString("0.00");
+                stars.CountStars = 0;
+                starsLabel.Text = stars.CountStars.ToString("0.00");
             });
 
             AddStep(@"Hit! :D", delegate
@@ -91,8 +91,8 @@ namespace osu.Desktop.VisualTests.Tests
 
             AddStep(@"Alter stars", delegate
             {
-                stars.Count = RNG.NextSingle() * (stars.StarCount + 1);
-                starsLabel.Text = stars.Count.ToString("0.00");
+                stars.CountStars = RNG.NextSingle() * (stars.StarCount + 1);
+                starsLabel.Text = stars.CountStars.ToString("0.00");
             });
 
             AddStep(@"Stop counters", delegate
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseScrollingHitObjects.cs b/osu.Desktop.VisualTests/Tests/TestCaseScrollingHitObjects.cs
index 9f439fe193..8e5cf8687c 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseScrollingHitObjects.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseScrollingHitObjects.cs
@@ -55,7 +55,7 @@ namespace osu.Desktop.VisualTests.Tests
             timeRangeBindable.ValueChanged += v => timeRangeText.Text = $"Visible Range: {v:#,#.#}";
             timeRangeBindable.ValueChanged += v => bottomLabel.Text = $"t minus {v:#,#}";
 
-            Add(new Drawable[]
+            AddRange(new Drawable[]
             {
                 new Container
                 {
diff --git a/osu.Desktop/Overlays/VersionManager.cs b/osu.Desktop/Overlays/VersionManager.cs
index 9182f925e1..0a10a60dca 100644
--- a/osu.Desktop/Overlays/VersionManager.cs
+++ b/osu.Desktop/Overlays/VersionManager.cs
@@ -202,7 +202,7 @@ namespace osu.Desktop.Overlays
             {
                 this.game = game;
 
-                IconContent.Add(new Drawable[]
+                IconContent.AddRange(new Drawable[]
                 {
                     new Box
                     {
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs
index e52fb1362f..17b0b0a607 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs
@@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
             RelativeSizeAxes = Axes.Both;
             Height = (float)HitObject.Duration;
 
-            Add(new Drawable[]
+            AddRange(new Drawable[]
             {
                 // For now the body piece covers the entire height of the container
                 // whereas possibly in the future we don't want to extend under the head/tail.
diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs
index 53eedea073..e80ac933c8 100644
--- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs
+++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs
@@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Osu.UI
             Anchor = Anchor.Centre;
             Origin = Anchor.Centre;
 
-            Add(new Drawable[]
+            AddRange(new Drawable[]
             {
                 connectionLayer = new FollowPointRenderer
                 {
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CirclePiece.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CirclePiece.cs
index 709343d086..3f8249f5a9 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CirclePiece.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CirclePiece.cs
@@ -68,7 +68,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces
         {
             EarlyActivationMilliseconds = pre_beat_transition_time;
 
-            AddInternal(new Drawable[]
+            AddRangeInternal(new Drawable[]
             {
                 background = new CircularContainer
                 {
diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs
index 0ad7969c78..bb679e5150 100644
--- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs
+++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs
@@ -54,7 +54,7 @@ namespace osu.Game.Rulesets.Taiko.UI
 
         public TaikoPlayfield()
         {
-            AddInternal(new Drawable[]
+            AddRangeInternal(new Drawable[]
             {
                 new ScaleFixContainer
                 {
diff --git a/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs b/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs
index f4ac01c0f1..cfa98da3c8 100644
--- a/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs
+++ b/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs
@@ -140,7 +140,7 @@ namespace osu.Game.Beatmaps.Drawables
                                 },
                                 starCounter = new StarCounter
                                 {
-                                    Count = (float)beatmap.StarDifficulty,
+                                    CountStars = (float)beatmap.StarDifficulty,
                                     Scale = new Vector2(0.8f),
                                 }
                             }
diff --git a/osu.Game/Graphics/Containers/SectionsContainer.cs b/osu.Game/Graphics/Containers/SectionsContainer.cs
index 5fdb5e869e..1d792f1b78 100644
--- a/osu.Game/Graphics/Containers/SectionsContainer.cs
+++ b/osu.Game/Graphics/Containers/SectionsContainer.cs
@@ -93,7 +93,7 @@ namespace osu.Game.Graphics.Containers
                 sections = value.ToList();
                 if (sections.Count == 0) return;
 
-                sectionsContainer.Add(sections);
+                sectionsContainer.AddRange(sections);
                 SelectedSection.Value = sections[0];
                 lastKnownScroll = float.NaN;
             }
diff --git a/osu.Game/Graphics/UserInterface/BarGraph.cs b/osu.Game/Graphics/UserInterface/BarGraph.cs
index e4a471bbba..87b4ab9e40 100644
--- a/osu.Game/Graphics/UserInterface/BarGraph.cs
+++ b/osu.Game/Graphics/UserInterface/BarGraph.cs
@@ -58,7 +58,7 @@ namespace osu.Game.Graphics.UserInterface
                             Direction = Direction,
                         });
                 //I'm using ToList() here because Where() returns an Enumerable which can change it's elements afterwards
-                Remove(Children.Where((bar, index) => index >= value.Count()).ToList());
+                RemoveRange(Children.Where((bar, index) => index >= value.Count()).ToList());
             }
         }
     }
diff --git a/osu.Game/Graphics/UserInterface/OsuButton.cs b/osu.Game/Graphics/UserInterface/OsuButton.cs
index 6814308cb4..18156f8e76 100644
--- a/osu.Game/Graphics/UserInterface/OsuButton.cs
+++ b/osu.Game/Graphics/UserInterface/OsuButton.cs
@@ -49,7 +49,7 @@ namespace osu.Game.Graphics.UserInterface
             Content.Masking = true;
             Content.CornerRadius = 5;
 
-            Add(new Drawable[]
+            AddRange(new Drawable[]
             {
                 new Triangles
                 {
diff --git a/osu.Game/Graphics/UserInterface/SearchTextBox.cs b/osu.Game/Graphics/UserInterface/SearchTextBox.cs
index 39db8d8be7..0d852e4276 100644
--- a/osu.Game/Graphics/UserInterface/SearchTextBox.cs
+++ b/osu.Game/Graphics/UserInterface/SearchTextBox.cs
@@ -17,7 +17,7 @@ namespace osu.Game.Graphics.UserInterface
         public SearchTextBox()
         {
             Height = 35;
-            Add(new Drawable[]
+            AddRange(new Drawable[]
             {
                 new TextAwesome
                 {
diff --git a/osu.Game/Graphics/UserInterface/StarCounter.cs b/osu.Game/Graphics/UserInterface/StarCounter.cs
index 295cdac81d..490ea6e64a 100644
--- a/osu.Game/Graphics/UserInterface/StarCounter.cs
+++ b/osu.Game/Graphics/UserInterface/StarCounter.cs
@@ -33,25 +33,25 @@ namespace osu.Game.Graphics.UserInterface
         private const float star_size = 20;
         private const float star_spacing = 4;
 
-        private float count;
+        private float countStars;
 
         /// <summary>
         /// Amount of stars represented.
         /// </summary>
-        public float Count
+        public float CountStars
         {
             get
             {
-                return count;
+                return countStars;
             }
 
             set
             {
-                if (count == value) return;
+                if (countStars == value) return;
 
                 if (IsLoaded)
                     transformCount(value);
-                count = value;
+                countStars = value;
             }
         }
 
@@ -94,15 +94,15 @@ namespace osu.Game.Graphics.UserInterface
 
         public void ResetCount()
         {
-            count = 0;
+            countStars = 0;
             StopAnimation();
         }
 
         public void ReplayAnimation()
         {
-            var t = count;
+            var t = countStars;
             ResetCount();
-            Count = t;
+            CountStars = t;
         }
 
         public void StopAnimation()
@@ -111,8 +111,8 @@ namespace osu.Game.Graphics.UserInterface
             foreach (var star in stars.Children)
             {
                 star.ClearTransforms(true);
-                star.FadeTo(i < count ? 1.0f : minStarAlpha);
-                star.Icon.ScaleTo(getStarScale(i, count));
+                star.FadeTo(i < countStars ? 1.0f : minStarAlpha);
+                star.Icon.ScaleTo(getStarScale(i, countStars));
                 i++;
             }
         }
@@ -132,7 +132,7 @@ namespace osu.Game.Graphics.UserInterface
             {
                 star.ClearTransforms(true);
 
-                var delay = (count <= newValue ? Math.Max(i - count, 0) : Math.Max(count - 1 - i, 0)) * animationDelay;
+                var delay = (countStars <= newValue ? Math.Max(i - countStars, 0) : Math.Max(countStars - 1 - i, 0)) * animationDelay;
 
                 using (BeginDelayedSequence(delay, true))
                 {
diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs
index 7e5b913d10..961e296050 100644
--- a/osu.Game/OsuGame.cs
+++ b/osu.Game/OsuGame.cs
@@ -141,7 +141,7 @@ namespace osu.Game
         {
             base.LoadComplete();
 
-            Add(new Drawable[] {
+            AddRange(new Drawable[] {
                 new VolumeControlReceptor
                 {
                     RelativeSizeAxes = Axes.Both,
diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs
index e8bde11a3c..f8b7c7e581 100644
--- a/osu.Game/Overlays/Chat/DrawableChannel.cs
+++ b/osu.Game/Overlays/Chat/DrawableChannel.cs
@@ -67,7 +67,7 @@ namespace osu.Game.Overlays.Chat
             var displayMessages = newMessages.Skip(Math.Max(0, newMessages.Count() - Channel.MAX_HISTORY));
 
             //up to last Channel.MAX_HISTORY messages
-            flow.Add(displayMessages.Select(m => new ChatLine(m)));
+            flow.AddRange(displayMessages.Select(m => new ChatLine(m)));
 
             if (!IsLoaded) return;
 
diff --git a/osu.Game/Overlays/Mods/ModButton.cs b/osu.Game/Overlays/Mods/ModButton.cs
index a7e7bb53b5..aca73d2828 100644
--- a/osu.Game/Overlays/Mods/ModButton.cs
+++ b/osu.Game/Overlays/Mods/ModButton.cs
@@ -199,7 +199,7 @@ namespace osu.Game.Overlays.Mods
             iconsContainer.Clear();
             if (Mods.Length > 1)
             {
-                iconsContainer.Add(new[]
+                iconsContainer.AddRange(new[]
                 {
                     backgroundIcon = new ModIcon(Mods[1])
                     {
diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs
index 74cced5ee9..f5613d6656 100644
--- a/osu.Game/Overlays/Notifications/Notification.cs
+++ b/osu.Game/Overlays/Notifications/Notification.cs
@@ -49,7 +49,7 @@ namespace osu.Game.Overlays.Notifications
             RelativeSizeAxes = Axes.X;
             AutoSizeAxes = Axes.Y;
 
-            AddInternal(new Drawable[]
+            AddRangeInternal(new Drawable[]
             {
                 Light = new NotificationLight
                 {
diff --git a/osu.Game/Overlays/Notifications/NotificationSection.cs b/osu.Game/Overlays/Notifications/NotificationSection.cs
index b4f35be733..831b09e7e9 100644
--- a/osu.Game/Overlays/Notifications/NotificationSection.cs
+++ b/osu.Game/Overlays/Notifications/NotificationSection.cs
@@ -69,7 +69,7 @@ namespace osu.Game.Overlays.Notifications
                 Left = 20,
             };
 
-            AddInternal(new Drawable[]
+            AddRangeInternal(new Drawable[]
             {
                 new Container
                 {
diff --git a/osu.Game/Overlays/Notifications/SimpleNotification.cs b/osu.Game/Overlays/Notifications/SimpleNotification.cs
index 2ac93b2ada..42604658de 100644
--- a/osu.Game/Overlays/Notifications/SimpleNotification.cs
+++ b/osu.Game/Overlays/Notifications/SimpleNotification.cs
@@ -42,7 +42,7 @@ namespace osu.Game.Overlays.Notifications
 
         public SimpleNotification()
         {
-            IconContent.Add(new Drawable[]
+            IconContent.AddRange(new Drawable[]
             {
                 IconBackgound = new Box
                 {
diff --git a/osu.Game/Overlays/Settings/SettingsSection.cs b/osu.Game/Overlays/Settings/SettingsSection.cs
index 2e3dc1ada2..77bf87f718 100644
--- a/osu.Game/Overlays/Settings/SettingsSection.cs
+++ b/osu.Game/Overlays/Settings/SettingsSection.cs
@@ -44,7 +44,7 @@ namespace osu.Game.Overlays.Settings
             const int header_size = 26;
             const int header_margin = 25;
             const int border_size = 2;
-            AddInternal(new Drawable[]
+            AddRangeInternal(new Drawable[]
             {
                 new Box
                 {
diff --git a/osu.Game/Overlays/Settings/SettingsSubsection.cs b/osu.Game/Overlays/Settings/SettingsSubsection.cs
index 14082aa4db..0a9f7ba5d0 100644
--- a/osu.Game/Overlays/Settings/SettingsSubsection.cs
+++ b/osu.Game/Overlays/Settings/SettingsSubsection.cs
@@ -33,7 +33,7 @@ namespace osu.Game.Overlays.Settings
             RelativeSizeAxes = Axes.X;
             AutoSizeAxes = Axes.Y;
             Direction = FillDirection.Vertical;
-            AddInternal(new Drawable[]
+            AddRangeInternal(new Drawable[]
             {
                 new OsuSpriteText
                 {
diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs
index fd87fd1b38..24fee10195 100644
--- a/osu.Game/Screens/Menu/ButtonSystem.cs
+++ b/osu.Game/Screens/Menu/ButtonSystem.cs
@@ -114,8 +114,8 @@ namespace osu.Game.Screens.Menu
             buttonsTopLevel.Add(new Button(@"osu!direct", string.Empty, FontAwesome.fa_osu_chevron_down_o, new Color4(165, 204, 0, 255), () => OnDirect?.Invoke(), 0, Key.D));
             buttonsTopLevel.Add(new Button(@"exit", string.Empty, FontAwesome.fa_osu_cross_o, new Color4(238, 51, 153, 255), onExit, 0, Key.Q));
 
-            buttonFlow.Add(buttonsPlay);
-            buttonFlow.Add(buttonsTopLevel);
+            buttonFlow.AddRange(buttonsPlay);
+            buttonFlow.AddRange(buttonsTopLevel);
         }
 
         [BackgroundDependencyLoader(true)]
diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs
index 20a8f73104..e507055d5f 100644
--- a/osu.Game/Screens/Play/KeyCounter.cs
+++ b/osu.Game/Screens/Play/KeyCounter.cs
@@ -20,15 +20,15 @@ namespace osu.Game.Screens.Play
         private SpriteText countSpriteText;
 
         public bool IsCounting { get; set; }
-        private int count;
-        public int Count
+        private int countPresses;
+        public int CountPresses
         {
-            get { return count; }
+            get { return countPresses; }
             private set
             {
-                if (count != value)
+                if (countPresses != value)
                 {
-                    count = value;
+                    countPresses = value;
                     countSpriteText.Text = value.ToString(@"#,0");
                 }
             }
@@ -45,7 +45,7 @@ namespace osu.Game.Screens.Play
                     isLit = value;
                     updateGlowSprite(value);
                     if (value && IsCounting)
-                        Count++;
+                        CountPresses++;
                 }
             }
         }
@@ -98,7 +98,7 @@ namespace osu.Game.Screens.Play
                         },
                         countSpriteText = new OsuSpriteText
                         {
-                            Text = Count.ToString(@"#,0"),
+                            Text = CountPresses.ToString(@"#,0"),
                             Anchor = Anchor.Centre,
                             Origin = Anchor.Centre,
                             RelativePositionAxes = Axes.Both,
@@ -128,6 +128,6 @@ namespace osu.Game.Screens.Play
             }
         }
 
-        public void ResetCount() => Count = 0;
+        public void ResetCount() => CountPresses = 0;
     }
 }
diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs
index d0ffe1de1c..b0d3a99603 100644
--- a/osu.Game/Screens/Play/Player.cs
+++ b/osu.Game/Screens/Play/Player.cs
@@ -200,7 +200,7 @@ namespace osu.Game.Screens.Play
 
             scoreProcessor = HitRenderer.CreateScoreProcessor();
 
-            hudOverlay.KeyCounter.Add(rulesetInstance.CreateGameplayKeys());
+            hudOverlay.KeyCounter.AddRange(rulesetInstance.CreateGameplayKeys());
             hudOverlay.BindProcessor(scoreProcessor);
             hudOverlay.BindHitRenderer(HitRenderer);
 
diff --git a/osu.Game/Screens/Ranking/ResultsPage.cs b/osu.Game/Screens/Ranking/ResultsPage.cs
index d0a1c49119..59173748ed 100644
--- a/osu.Game/Screens/Ranking/ResultsPage.cs
+++ b/osu.Game/Screens/Ranking/ResultsPage.cs
@@ -40,7 +40,7 @@ namespace osu.Game.Screens.Ranking
         [BackgroundDependencyLoader]
         private void load(OsuColour colours)
         {
-            AddInternal(new Drawable[]
+            AddRangeInternal(new Drawable[]
             {
                 fill = new Box
                 {
diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs
index f9064c4963..647cac5bbe 100644
--- a/osu.Game/Screens/Select/BeatmapCarousel.cs
+++ b/osu.Game/Screens/Select/BeatmapCarousel.cs
@@ -12,7 +12,6 @@ using osu.Game.Beatmaps.Drawables;
 using osu.Game.Configuration;
 using osu.Framework.Input;
 using OpenTK.Input;
-using System.Collections;
 using osu.Framework.MathUtils;
 using System.Diagnostics;
 using System.Threading.Tasks;
@@ -22,7 +21,7 @@ using osu.Framework.Configuration;
 
 namespace osu.Game.Screens.Select
 {
-    internal class BeatmapCarousel : ScrollContainer, IEnumerable<BeatmapGroup>
+    internal class BeatmapCarousel : ScrollContainer
     {
         public BeatmapInfo SelectedBeatmap => selectedPanel?.Beatmap;
 
@@ -265,10 +264,6 @@ namespace osu.Game.Screens.Select
                 perform();
         }
 
-        public IEnumerator<BeatmapGroup> GetEnumerator() => groups.GetEnumerator();
-
-        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
-
         private BeatmapGroup createGroup(BeatmapSetInfo beatmapSet)
         {
             foreach (var b in beatmapSet.Beatmaps)
@@ -307,7 +302,7 @@ namespace osu.Game.Screens.Select
                 panels.Remove(p);
 
             scrollableContent.Remove(group.Header);
-            scrollableContent.Remove(group.BeatmapPanels);
+            scrollableContent.RemoveRange(group.BeatmapPanels);
 
             if (selectedGroup == group)
                 SelectNext();
diff --git a/osu.Game/Screens/Select/BeatmapDetailArea.cs b/osu.Game/Screens/Select/BeatmapDetailArea.cs
index d116e5b159..47d25585ad 100644
--- a/osu.Game/Screens/Select/BeatmapDetailArea.cs
+++ b/osu.Game/Screens/Select/BeatmapDetailArea.cs
@@ -33,7 +33,7 @@ namespace osu.Game.Screens.Select
 
         public BeatmapDetailArea()
         {
-            AddInternal(new Drawable[]
+            AddRangeInternal(new Drawable[]
             {
                 new BeatmapDetailAreaTabControl
                 {
@@ -61,7 +61,7 @@ namespace osu.Game.Screens.Select
                 },
             });
 
-            Add(new Drawable[]
+            AddRange(new Drawable[]
             {
                 Details = new BeatmapDetails
                 {

From 6209f193e39490689f9e7ab84fd2af1fc4ffe899 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thomas=20M=C3=BCller?= <thomas94@gmx.net>
Date: Tue, 11 Jul 2017 21:21:58 +0300
Subject: [PATCH 39/41] Update framework

---
 osu-framework | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/osu-framework b/osu-framework
index 40dc967472..38363de3d4 160000
--- a/osu-framework
+++ b/osu-framework
@@ -1 +1 @@
-Subproject commit 40dc96747288fab4ae137e74b0af7452dc8be792
+Subproject commit 38363de3d466c60d668159745826df239318f875

From c8c1dcae2853be5ad65b86d8de30aad19c943458 Mon Sep 17 00:00:00 2001
From: Dean Herbert <pe@ppy.sh>
Date: Wed, 12 Jul 2017 12:55:40 +0900
Subject: [PATCH 40/41] Fix incorrect filename

---
 ...hFillFlowContainer.cs => ReverseChildIDFillFlowContainer.cs} | 0
 osu.Game/osu.Game.csproj                                        | 2 +-
 2 files changed, 1 insertion(+), 1 deletion(-)
 rename osu.Game/Graphics/Containers/{ReverseDepthFillFlowContainer.cs => ReverseChildIDFillFlowContainer.cs} (100%)

diff --git a/osu.Game/Graphics/Containers/ReverseDepthFillFlowContainer.cs b/osu.Game/Graphics/Containers/ReverseChildIDFillFlowContainer.cs
similarity index 100%
rename from osu.Game/Graphics/Containers/ReverseDepthFillFlowContainer.cs
rename to osu.Game/Graphics/Containers/ReverseChildIDFillFlowContainer.cs
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 0b5bab2b45..3d84f287f0 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -475,7 +475,7 @@
     <Compile Include="Overlays\Direct\DirectListPanel.cs" />
     <Compile Include="Database\OnlineWorkingBeatmap.cs" />
     <Compile Include="Database\BeatmapOnlineInfo.cs" />
-    <Compile Include="Graphics\Containers\ReverseDepthFillFlowContainer.cs" />
+    <Compile Include="Graphics\Containers\ReverseChildIDFillFlowContainer.cs" />
     <Compile Include="Database\RankStatus.cs" />
     <Compile Include="Overlays\SearchableList\SearchableListHeader.cs" />
     <Compile Include="Overlays\SearchableList\HeaderTabControl.cs" />

From e1e7cb71781ef3a97b2a9eafcbb98049207f3805 Mon Sep 17 00:00:00 2001
From: Dean Herbert <pe@ppy.sh>
Date: Wed, 12 Jul 2017 12:55:52 +0900
Subject: [PATCH 41/41] Remove unnecessary using statements

---
 osu.Game/Rulesets/Timing/DrawableTimingSection.cs | 2 --
 1 file changed, 2 deletions(-)

diff --git a/osu.Game/Rulesets/Timing/DrawableTimingSection.cs b/osu.Game/Rulesets/Timing/DrawableTimingSection.cs
index 74ff721d50..6345a566c2 100644
--- a/osu.Game/Rulesets/Timing/DrawableTimingSection.cs
+++ b/osu.Game/Rulesets/Timing/DrawableTimingSection.cs
@@ -1,13 +1,11 @@
 // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
 // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
 
-using System.Collections.Generic;
 using System.Linq;
 using osu.Framework.Caching;
 using osu.Framework.Configuration;
 using osu.Framework.Graphics;
 using osu.Framework.Graphics.Containers;
-using osu.Game.Rulesets.Objects;
 using osu.Game.Rulesets.Objects.Drawables;
 using OpenTK;
 using osu.Game.Rulesets.Objects.Types;