From 8cbcb0e74f8aea2cc0e4830ab489f882233ba234 Mon Sep 17 00:00:00 2001 From: UltraDrakon Date: Tue, 6 Jan 2026 14:51:07 +0100 Subject: [PATCH 1/2] Hide cursor during background reveal in song select - Implement IProvideCursor in SongSelect to hide cursor when background is revealed - Cursor reappears on mouse movement and hides again after 1 second of inactivity - Fix MenuCursorContainer to preserve drag rotation state during hide/show cycles --- .../Graphics/Cursor/MenuCursorContainer.cs | 10 +++++--- osu.Game/Screens/SelectV2/SongSelect.cs | 25 ++++++++++++++++++- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/osu.Game/Graphics/Cursor/MenuCursorContainer.cs b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs index 696ea62b42..2ea30d86bd 100644 --- a/osu.Game/Graphics/Cursor/MenuCursorContainer.cs +++ b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs @@ -220,16 +220,18 @@ namespace osu.Game.Graphics.Cursor { activeCursor.FadeTo(1, 250, Easing.OutQuint); activeCursor.ScaleTo(1, 400, Easing.OutQuint); - activeCursor.RotateTo(0, 400, Easing.OutQuint); - dragRotationState = DragRotationState.NotDragging; + + if (dragRotationState == DragRotationState.NotDragging) + activeCursor.RotateTo(0, 400, Easing.OutQuint); } protected override void PopOut() { activeCursor.FadeTo(0, 250, Easing.OutQuint); activeCursor.ScaleTo(0.6f, 250, Easing.In); - activeCursor.RotateTo(0, 400, Easing.OutQuint); - dragRotationState = DragRotationState.NotDragging; + + if (dragRotationState == DragRotationState.NotDragging) + activeCursor.RotateTo(0, 400, Easing.OutQuint); } private void playTapSample(double baseFrequency = 1f) diff --git a/osu.Game/Screens/SelectV2/SongSelect.cs b/osu.Game/Screens/SelectV2/SongSelect.cs index 4bee63b57c..e0e6e8842a 100644 --- a/osu.Game/Screens/SelectV2/SongSelect.cs +++ b/osu.Game/Screens/SelectV2/SongSelect.cs @@ -64,7 +64,7 @@ namespace osu.Game.Screens.SelectV2 /// This will be gradually built upon and ultimately replace once everything is in place. /// [Cached(typeof(ISongSelect))] - public abstract partial class SongSelect : ScreenWithBeatmapBackground, IKeyBindingHandler, ISongSelect, IHandlePresentBeatmap + public abstract partial class SongSelect : ScreenWithBeatmapBackground, IKeyBindingHandler, ISongSelect, IHandlePresentBeatmap, IProvideCursor { /// /// A debounce that governs how long after a panel is selected before the rest of song select (and the game at large) @@ -911,6 +911,23 @@ namespace osu.Game.Screens.SelectV2 #region Input private ScheduledDelegate? revealingBackground; + private bool isRevealingBackground; + private double? lastCursorMoveTimeDuringReveal; + + private bool cursorRecentlyMoved => lastCursorMoveTimeDuringReveal.HasValue && + Clock.CurrentTime - lastCursorMoveTimeDuringReveal.Value < 1000; + + public CursorContainer? Cursor => null; + public bool ProvidingUserCursor => isRevealingBackground && !cursorRecentlyMoved; + + protected override bool OnHover(HoverEvent e) => true; + + protected override bool OnMouseMove(MouseMoveEvent e) + { + if (isRevealingBackground) + lastCursorMoveTimeDuringReveal = Clock.CurrentTime; + return base.OnMouseMove(e); + } private GridContainer mainGridContainer = null!; @@ -948,6 +965,9 @@ namespace osu.Game.Screens.SelectV2 updateBackgroundDim(); Footer?.Hide(); + + isRevealingBackground = true; + lastCursorMoveTimeDuringReveal = null; }, 200); } @@ -981,6 +1001,9 @@ namespace osu.Game.Screens.SelectV2 revealingBackground.Cancel(); revealingBackground = null; + isRevealingBackground = false; + lastCursorMoveTimeDuringReveal = null; + updateBackgroundDim(); } From 1c1a3fbe8d8f347abd5a7764085c44808c56c291 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Jan 2026 18:00:12 +0900 Subject: [PATCH 2/2] Simplify logic --- osu.Game/Screens/SelectV2/SongSelect.cs | 48 +++++++++---------------- 1 file changed, 17 insertions(+), 31 deletions(-) diff --git a/osu.Game/Screens/SelectV2/SongSelect.cs b/osu.Game/Screens/SelectV2/SongSelect.cs index e0e6e8842a..e25597b642 100644 --- a/osu.Game/Screens/SelectV2/SongSelect.cs +++ b/osu.Game/Screens/SelectV2/SongSelect.cs @@ -119,6 +119,8 @@ namespace osu.Game.Screens.SelectV2 private Container mainContent = null!; private SkinnableContainer skinnableContent = null!; + private GridContainer mainGridContainer = null!; + private NoResultsPlaceholder noResultsPlaceholder = null!; public override bool? ApplyModTrackAdjustments => true; @@ -812,7 +814,7 @@ namespace osu.Game.Screens.SelectV2 // Probably needs more thought because this needs to be in every `ApplyToBackground` currently to restore sane defaults. backgroundModeBeatmap.FadeColour(Color4.White, 250); - bool backgroundRevealActive = revealingBackground?.State == ScheduledDelegate.RunState.Running || revealingBackground?.State == ScheduledDelegate.RunState.Complete; + bool backgroundRevealActive = revealBackgroundDelegate?.State == ScheduledDelegate.RunState.Running || revealBackgroundDelegate?.State == ScheduledDelegate.RunState.Complete; backgroundModeBeatmap.BlurAmount.Value = configBackgroundBlur.Value && !backgroundRevealActive ? 20 : 0f; }); @@ -908,29 +910,15 @@ namespace osu.Game.Screens.SelectV2 #endregion - #region Input + #region Background reveal - private ScheduledDelegate? revealingBackground; - private bool isRevealingBackground; - private double? lastCursorMoveTimeDuringReveal; - - private bool cursorRecentlyMoved => lastCursorMoveTimeDuringReveal.HasValue && - Clock.CurrentTime - lastCursorMoveTimeDuringReveal.Value < 1000; + private ScheduledDelegate? revealBackgroundDelegate; public CursorContainer? Cursor => null; - public bool ProvidingUserCursor => isRevealingBackground && !cursorRecentlyMoved; + bool IProvideCursor.ProvidingUserCursor => revealBackgroundDelegate?.Completed == true; protected override bool OnHover(HoverEvent e) => true; - protected override bool OnMouseMove(MouseMoveEvent e) - { - if (isRevealingBackground) - lastCursorMoveTimeDuringReveal = Clock.CurrentTime; - return base.OnMouseMove(e); - } - - private GridContainer mainGridContainer = null!; - protected override bool OnMouseDown(MouseDownEvent e) { var containingInputManager = GetContainingInputManager(); @@ -944,13 +932,13 @@ namespace osu.Game.Screens.SelectV2 // For simplicity, disable this functionality on mobile. bool isTouchInput = e.CurrentState.Mouse.LastSource is ISourcedFromTouch; - if (!carousel.AbsoluteScrolling && !isTouchInput && mouseDownPriority && revealingBackground == null) + if (!carousel.AbsoluteScrolling && !isTouchInput && mouseDownPriority && revealBackgroundDelegate == null) { - revealingBackground = Scheduler.AddDelayed(() => + revealBackgroundDelegate = Scheduler.AddDelayed(() => { if (containingInputManager.DraggedDrawable != null) { - revealingBackground = null; + revealBackgroundDelegate = null; return; } @@ -965,9 +953,6 @@ namespace osu.Game.Screens.SelectV2 updateBackgroundDim(); Footer?.Hide(); - - isRevealingBackground = true; - lastCursorMoveTimeDuringReveal = null; }, 200); } @@ -982,10 +967,10 @@ namespace osu.Game.Screens.SelectV2 private void restoreBackground() { - if (revealingBackground == null) + if (revealBackgroundDelegate == null) return; - if (revealingBackground.State == ScheduledDelegate.RunState.Complete) + if (revealBackgroundDelegate.State == ScheduledDelegate.RunState.Complete) { mainContent.ResizeWidthTo(1f, 500, Easing.OutQuint); mainContent.ScaleTo(1, 500, Easing.OutQuint); @@ -998,15 +983,16 @@ namespace osu.Game.Screens.SelectV2 Footer?.Show(); } - revealingBackground.Cancel(); - revealingBackground = null; - - isRevealingBackground = false; - lastCursorMoveTimeDuringReveal = null; + revealBackgroundDelegate.Cancel(); + revealBackgroundDelegate = null; updateBackgroundDim(); } + #endregion + + #region Input + public virtual bool OnPressed(KeyBindingPressEvent e) { if (!this.IsCurrentScreen()) return false;