From 90b9fb0809f18a2ca5c6c1f0670bab57712af5cd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Jun 2025 19:10:06 +0900 Subject: [PATCH] Store input padding adjustments in `CarouselItem` to allow more reliable inflation --- .../TestSceneBeatmapCarouselArtistGrouping.cs | 5 ++--- ...estSceneBeatmapCarouselDifficultyGrouping.cs | 1 - .../TestSceneBeatmapCarouselNoGrouping.cs | 12 ++++++------ osu.Game/Graphics/Carousel/Carousel.cs | 4 ++++ osu.Game/Graphics/Carousel/CarouselItem.cs | 17 +++++++++++++++++ osu.Game/Screens/SelectV2/Panel.cs | 17 +++++++++++++---- osu.Game/Screens/SelectV2/PanelBeatmap.cs | 13 ------------- osu.Game/Screens/SelectV2/PanelBeatmapSet.cs | 13 ------------- .../Screens/SelectV2/PanelBeatmapStandalone.cs | 16 ---------------- 9 files changed, 42 insertions(+), 56 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselArtistGrouping.cs b/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselArtistGrouping.cs index dad987ab60..15ae35ad28 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselArtistGrouping.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselArtistGrouping.cs @@ -177,7 +177,6 @@ namespace osu.Game.Tests.Visual.SongSelectV2 } [Test] - [Ignore("broken")] public void TestInputHandlingWithinGaps() { AddAssert("no beatmaps visible", () => !GetVisiblePanels().Any()); @@ -204,10 +203,10 @@ namespace osu.Game.Tests.Visual.SongSelectV2 ClickVisiblePanelWithOffset(0, new Vector2(0, -(CarouselItem.DEFAULT_HEIGHT / 2 + 1))); WaitForGroupSelection(0, 1); - ClickVisiblePanelWithOffset(1, new Vector2(0, (CarouselItem.DEFAULT_HEIGHT / 2 + 1))); + ClickVisiblePanelWithOffset(1, new Vector2(0, CarouselItem.DEFAULT_HEIGHT / 2 + 1)); WaitForGroupSelection(0, 2); - ClickVisiblePanelWithOffset(1, new Vector2(0, (CarouselItem.DEFAULT_HEIGHT / 2 + 1))); + ClickVisiblePanelWithOffset(1, new Vector2(0, CarouselItem.DEFAULT_HEIGHT / 2 + 1)); WaitForGroupSelection(0, 5); } diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselDifficultyGrouping.cs b/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselDifficultyGrouping.cs index 61ecf38637..8f7c901c37 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselDifficultyGrouping.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselDifficultyGrouping.cs @@ -170,7 +170,6 @@ namespace osu.Game.Tests.Visual.SongSelectV2 } [Test] - [Ignore("broken")] public void TestInputHandlingWithinGaps() { AddAssert("no beatmaps visible", () => !GetVisiblePanels().Any()); diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselNoGrouping.cs b/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselNoGrouping.cs index 84e7d38239..8a173d3e71 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselNoGrouping.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselNoGrouping.cs @@ -5,7 +5,6 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Testing; using osu.Game.Beatmaps; -using osu.Game.Graphics.Carousel; using osu.Game.Screens.Select.Filter; using osu.Game.Screens.SelectV2; using osuTK; @@ -259,7 +258,6 @@ namespace osu.Game.Tests.Visual.SongSelectV2 } [Test] - [Ignore("broken")] public void TestInputHandlingWithinGaps() { AddBeatmaps(2, 5); @@ -278,14 +276,16 @@ namespace osu.Game.Tests.Visual.SongSelectV2 WaitForSelection(0, 0); // Beatmap panels expand their selection area to cover holes from spacing. - ClickVisiblePanelWithOffset(1, new Vector2(0, -(CarouselItem.DEFAULT_HEIGHT / 2 + 1))); + ClickVisiblePanelWithOffset(0, new Vector2(0, -(PanelBeatmap.HEIGHT / 2 + 1))); WaitForSelection(0, 0); - // Panels with higher depth will handle clicks in the gutters for simplicity. - ClickVisiblePanelWithOffset(2, new Vector2(0, (CarouselItem.DEFAULT_HEIGHT / 2 + 1))); + ClickVisiblePanelWithOffset(2, new Vector2(0, (PanelBeatmap.HEIGHT / 2 + 1))); WaitForSelection(0, 2); - ClickVisiblePanelWithOffset(3, new Vector2(0, (CarouselItem.DEFAULT_HEIGHT / 2 + 1))); + ClickVisiblePanelWithOffset(2, new Vector2(0, -(PanelBeatmap.HEIGHT / 2 + 1))); + WaitForSelection(0, 2); + + ClickVisiblePanelWithOffset(3, new Vector2(0, (PanelBeatmap.HEIGHT / 2 + 1))); WaitForSelection(0, 3); } diff --git a/osu.Game/Graphics/Carousel/Carousel.cs b/osu.Game/Graphics/Carousel/Carousel.cs index 8db0c683c2..2b1124eef1 100644 --- a/osu.Game/Graphics/Carousel/Carousel.cs +++ b/osu.Game/Graphics/Carousel/Carousel.cs @@ -395,6 +395,10 @@ namespace osu.Game.Graphics.Carousel offset += spacing; item.CarouselYPosition = offset; + item.CarouselInputLenienceAbove = spacing / 2; + if (previousVisible != null) + previousVisible.CarouselInputLenienceBelow = item.CarouselInputLenienceAbove; + if (item.IsVisible) { offset += item.DrawHeight; diff --git a/osu.Game/Graphics/Carousel/CarouselItem.cs b/osu.Game/Graphics/Carousel/CarouselItem.cs index 741e4d32fc..e1e93dd036 100644 --- a/osu.Game/Graphics/Carousel/CarouselItem.cs +++ b/osu.Game/Graphics/Carousel/CarouselItem.cs @@ -20,10 +20,27 @@ namespace osu.Game.Graphics.Carousel /// /// The current Y position in the carousel. + /// /// This is managed by and should not be set manually. /// public double CarouselYPosition { get; set; } + /// + /// The amount of input padding/lenience to be added to the area above this panel. + /// Calculated as half of the calculated spacing between this panel and the panel above it. + /// + /// This is managed by and should not be set manually. + /// + public float CarouselInputLenienceAbove { get; set; } + + /// + /// The amount of input padding/lenience to be added to the area below this panel. + /// Calculated as half of the calculated spacing between this panel and the panel below it. + /// + /// This is managed by and should not be set manually. + /// + public float CarouselInputLenienceBelow { get; set; } + /// /// The height this item will take when displayed. Defaults to . /// diff --git a/osu.Game/Screens/SelectV2/Panel.cs b/osu.Game/Screens/SelectV2/Panel.cs index f17567f9ba..f30c895a3b 100644 --- a/osu.Game/Screens/SelectV2/Panel.cs +++ b/osu.Game/Screens/SelectV2/Panel.cs @@ -68,10 +68,19 @@ namespace osu.Game.Screens.SelectV2 } } - // content is offset by PanelXOffset, make sure we only handle input at the actual visible - // offset region. - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => - TopLevelContent.ReceivePositionalInputAt(screenSpacePos); + public sealed override bool ReceivePositionalInputAt(Vector2 screenSpacePos) + { + var inputRectangle = TopLevelContent.DrawRectangle; + + // Cover the gaps introduced by the spacing between panels so that user mis-aims don't result in no-ops. + inputRectangle = inputRectangle.Inflate(new MarginPadding + { + Top = item!.CarouselInputLenienceAbove, + Bottom = item!.CarouselInputLenienceBelow, + }); + + return inputRectangle.Contains(TopLevelContent.ToLocalSpace(screenSpacePos)); + } [Resolved] private BeatmapCarousel? carousel { get; set; } diff --git a/osu.Game/Screens/SelectV2/PanelBeatmap.cs b/osu.Game/Screens/SelectV2/PanelBeatmap.cs index e785448c9a..19ff8a0676 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmap.cs +++ b/osu.Game/Screens/SelectV2/PanelBeatmap.cs @@ -72,19 +72,6 @@ namespace osu.Game.Screens.SelectV2 PanelXOffset = 60; } - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) - { - var inputRectangle = TopLevelContent.DrawRectangle; - - // Cover the gaps introduced by the spacing between BeatmapPanels so that clicks will not fall through the carousel. - // - // Caveat is that for simplicity, we are covering the full spacing, so panels with frontmost depth will have a slightly - // larger hit target. - inputRectangle = inputRectangle.Inflate(new MarginPadding { Vertical = BeatmapCarousel.SPACING }); - - return inputRectangle.Contains(TopLevelContent.ToLocalSpace(screenSpacePos)); - } - [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) { diff --git a/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs b/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs index e34e822e2d..425ca02e5a 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs +++ b/osu.Game/Screens/SelectV2/PanelBeatmapSet.cs @@ -67,19 +67,6 @@ namespace osu.Game.Screens.SelectV2 PanelXOffset = 20f; } - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) - { - var inputRectangle = TopLevelContent.DrawRectangle; - - // Cover the gaps introduced by the spacing between BeatmapPanels so that clicks will not fall through the carousel. - // - // Caveat is that for simplicity, we are covering the full spacing, so panels with frontmost depth will have a slightly - // larger hit target. - inputRectangle = inputRectangle.Inflate(new MarginPadding { Vertical = BeatmapCarousel.SPACING }); - - return inputRectangle.Contains(TopLevelContent.ToLocalSpace(screenSpacePos)); - } - [BackgroundDependencyLoader] private void load() { diff --git a/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.cs b/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.cs index d461653dcb..287af444ee 100644 --- a/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.cs +++ b/osu.Game/Screens/SelectV2/PanelBeatmapStandalone.cs @@ -71,22 +71,6 @@ namespace osu.Game.Screens.SelectV2 private OsuSpriteText authorText = null!; private FillFlowContainer mainFill = null!; - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) - { - var inputRectangle = TopLevelContent.DrawRectangle; - - if (Selected.Value) - { - // Cover the gaps introduced by the spacing between BeatmapPanels so that clicks will not fall through the carousel. - // - // Caveat is that for simplicity, we are covering the full spacing, so panels with frontmost depth will have a slightly - // larger hit target. - inputRectangle = inputRectangle.Inflate(new MarginPadding { Vertical = BeatmapCarousel.SPACING * 2 }); - } - - return inputRectangle.Contains(TopLevelContent.ToLocalSpace(screenSpacePos)); - } - public PanelBeatmapStandalone() { PanelXOffset = 20;