From 1ba8cc904a5b72693bad9f5309be5f4ae5f095fd Mon Sep 17 00:00:00 2001
From: jorolf <jorolf@gmx.de>
Date: Fri, 7 Feb 2020 21:42:47 +0100
Subject: [PATCH 1/3] Make the caret blink to the beat

---
 osu.Game/Graphics/UserInterface/OsuTextBox.cs | 46 +++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/osu.Game/Graphics/UserInterface/OsuTextBox.cs b/osu.Game/Graphics/UserInterface/OsuTextBox.cs
index f5b7bc3073..36740fb015 100644
--- a/osu.Game/Graphics/UserInterface/OsuTextBox.cs
+++ b/osu.Game/Graphics/UserInterface/OsuTextBox.cs
@@ -2,6 +2,7 @@
 // See the LICENCE file in the repository root for full licence text.
 
 using osu.Framework.Allocation;
+using osu.Framework.Audio.Track;
 using osu.Framework.Graphics;
 using osu.Framework.Graphics.Sprites;
 using osu.Framework.Graphics.UserInterface;
@@ -9,6 +10,9 @@ using osu.Game.Graphics.Sprites;
 using osuTK.Graphics;
 using osu.Framework.Extensions.Color4Extensions;
 using osu.Framework.Input.Events;
+using osu.Game.Beatmaps.ControlPoints;
+using osu.Game.Graphics.Containers;
+using osuTK;
 
 namespace osu.Game.Graphics.UserInterface
 {
@@ -59,5 +63,47 @@ namespace osu.Game.Graphics.UserInterface
         }
 
         protected override Drawable GetDrawableCharacter(char c) => new OsuSpriteText { Text = c.ToString(), Font = OsuFont.GetFont(size: CalculatedTextSize) };
+
+        protected override Caret CreateCaret() => new BeatCaret
+        {
+            CaretWidth = CaretWidth,
+            SelectionColour = SelectionColour,
+        };
+
+        private class BeatCaret : BasicCaret
+        {
+            private bool hasSelection;
+
+            public BeatCaret()
+            {
+                AddInternal(new CaretBeatSyncedContainer(this));
+            }
+
+            public override void DisplayAt(Vector2 position, float? selectionWidth)
+            {
+                base.DisplayAt(position, selectionWidth);
+
+                hasSelection = selectionWidth != null;
+                if (selectionWidth == null)
+                    ClearTransforms(targetMember: nameof(Alpha));
+            }
+
+            private class CaretBeatSyncedContainer : BeatSyncedContainer
+            {
+                private readonly BeatCaret caret;
+
+                public CaretBeatSyncedContainer(BeatCaret caret)
+                {
+                    this.caret = caret;
+                    MinimumBeatLength = 300;
+                }
+
+                protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes)
+                {
+                    if (!caret.hasSelection)
+                        caret.FadeTo(0.7f).FadeTo(0.4f, timingPoint.BeatLength, Easing.InOutSine);
+                }
+            }
+        }
     }
 }

From c2e0c83724f0d981c780d5a1fb337c84f4248db7 Mon Sep 17 00:00:00 2001
From: jorolf <jorolf@gmx.de>
Date: Sat, 8 Feb 2020 20:25:16 +0100
Subject: [PATCH 2/3] change the hierarchy layout

---
 osu.Game/Graphics/UserInterface/OsuTextBox.cs | 69 +++++++++++++++----
 1 file changed, 57 insertions(+), 12 deletions(-)

diff --git a/osu.Game/Graphics/UserInterface/OsuTextBox.cs b/osu.Game/Graphics/UserInterface/OsuTextBox.cs
index 36740fb015..d58a22685e 100644
--- a/osu.Game/Graphics/UserInterface/OsuTextBox.cs
+++ b/osu.Game/Graphics/UserInterface/OsuTextBox.cs
@@ -9,6 +9,7 @@ using osu.Framework.Graphics.UserInterface;
 using osu.Game.Graphics.Sprites;
 using osuTK.Graphics;
 using osu.Framework.Extensions.Color4Extensions;
+using osu.Framework.Graphics.Shapes;
 using osu.Framework.Input.Events;
 using osu.Game.Beatmaps.ControlPoints;
 using osu.Game.Graphics.Containers;
@@ -70,38 +71,82 @@ namespace osu.Game.Graphics.UserInterface
             SelectionColour = SelectionColour,
         };
 
-        private class BeatCaret : BasicCaret
+        private class BeatCaret : Caret
         {
-            private bool hasSelection;
+            private const float caret_move_time = 60;
+
+            private readonly CaretBeatSyncedContainer beatSync;
 
             public BeatCaret()
             {
-                AddInternal(new CaretBeatSyncedContainer(this));
+                RelativeSizeAxes = Axes.Y;
+                Size = new Vector2(1, 0.9f);
+
+                Colour = Color4.Transparent;
+                Anchor = Anchor.CentreLeft;
+                Origin = Anchor.CentreLeft;
+
+                Masking = true;
+                CornerRadius = 1;
+                InternalChild = beatSync = new CaretBeatSyncedContainer
+                {
+                    RelativeSizeAxes = Axes.Both,
+                };
             }
 
+            public override void Hide() => this.FadeOut(200);
+
+            public float CaretWidth { get; set; }
+
+            public Color4 SelectionColour { get; set; }
+
             public override void DisplayAt(Vector2 position, float? selectionWidth)
             {
-                base.DisplayAt(position, selectionWidth);
+                beatSync.HasSelection = selectionWidth != null;
 
-                hasSelection = selectionWidth != null;
-                if (selectionWidth == null)
-                    ClearTransforms(targetMember: nameof(Alpha));
+                if (selectionWidth != null)
+                {
+                    this.MoveTo(new Vector2(position.X, position.Y), 60, Easing.Out);
+                    this.ResizeWidthTo(selectionWidth.Value + CaretWidth / 2, caret_move_time, Easing.Out);
+                    this.FadeColour(SelectionColour, 200, Easing.Out);
+                }
+                else
+                {
+                    this.MoveTo(new Vector2(position.X - CaretWidth / 2, position.Y), 60, Easing.Out);
+                    this.ResizeWidthTo(CaretWidth, caret_move_time, Easing.Out);
+                    this.FadeColour(Color4.White, 200, Easing.Out);
+                }
             }
 
             private class CaretBeatSyncedContainer : BeatSyncedContainer
             {
-                private readonly BeatCaret caret;
+                private bool hasSelection;
 
-                public CaretBeatSyncedContainer(BeatCaret caret)
+                public bool HasSelection
+                {
+                    set
+                    {
+                        hasSelection = value;
+                        if (value)
+
+                            this.FadeTo(0.5f, 200, Easing.Out);
+                    }
+                }
+
+                public CaretBeatSyncedContainer()
                 {
-                    this.caret = caret;
                     MinimumBeatLength = 300;
+                    InternalChild = new Box
+                    {
+                        RelativeSizeAxes = Axes.Both,
+                        Colour = Color4.White,
+                    };
                 }
 
                 protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes)
                 {
-                    if (!caret.hasSelection)
-                        caret.FadeTo(0.7f).FadeTo(0.4f, timingPoint.BeatLength, Easing.InOutSine);
+                    if (!hasSelection)
+                        this.FadeTo(0.7f).FadeTo(0.4f, timingPoint.BeatLength, Easing.InOutSine);
                 }
             }
         }

From 93ff25d2a43ee62c40c46e4489515e51f39f5395 Mon Sep 17 00:00:00 2001
From: Dean Herbert <pe@ppy.sh>
Date: Sun, 9 Feb 2020 15:36:44 +0900
Subject: [PATCH 3/3] Rename caret class

---
 osu.Game/Graphics/UserInterface/OsuTextBox.cs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/osu.Game/Graphics/UserInterface/OsuTextBox.cs b/osu.Game/Graphics/UserInterface/OsuTextBox.cs
index d58a22685e..4abbf8db57 100644
--- a/osu.Game/Graphics/UserInterface/OsuTextBox.cs
+++ b/osu.Game/Graphics/UserInterface/OsuTextBox.cs
@@ -65,19 +65,19 @@ namespace osu.Game.Graphics.UserInterface
 
         protected override Drawable GetDrawableCharacter(char c) => new OsuSpriteText { Text = c.ToString(), Font = OsuFont.GetFont(size: CalculatedTextSize) };
 
-        protected override Caret CreateCaret() => new BeatCaret
+        protected override Caret CreateCaret() => new OsuCaret
         {
             CaretWidth = CaretWidth,
             SelectionColour = SelectionColour,
         };
 
-        private class BeatCaret : Caret
+        private class OsuCaret : Caret
         {
             private const float caret_move_time = 60;
 
             private readonly CaretBeatSyncedContainer beatSync;
 
-            public BeatCaret()
+            public OsuCaret()
             {
                 RelativeSizeAxes = Axes.Y;
                 Size = new Vector2(1, 0.9f);