mirror of
https://github.com/ppy/osu.git
synced 2026-06-06 01:33:50 +08:00
Merge pull request #33279 from peppy/song-select-v2-reset-scroll
SongSelectV2: Scroll to selection when mouse moves to left area
This commit is contained in:
@@ -22,6 +22,7 @@ using osu.Game.Beatmaps;
|
||||
using osu.Game.Collections;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Extensions;
|
||||
using osu.Game.Graphics.Carousel;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.API;
|
||||
@@ -52,11 +53,16 @@ using osu.Game.Screens.Select;
|
||||
using osu.Game.Screens.Select.Carousel;
|
||||
using osu.Game.Screens.Select.Leaderboards;
|
||||
using osu.Game.Screens.Select.Options;
|
||||
using osu.Game.Screens.SelectV2;
|
||||
using osu.Game.Tests.Beatmaps.IO;
|
||||
using osu.Game.Tests.Resources;
|
||||
using osu.Game.Utils;
|
||||
using osuTK;
|
||||
using osuTK.Input;
|
||||
using BeatmapCarousel = osu.Game.Screens.Select.BeatmapCarousel;
|
||||
using CollectionDropdown = osu.Game.Collections.CollectionDropdown;
|
||||
using FilterControl = osu.Game.Screens.Select.FilterControl;
|
||||
using FooterButtonRandom = osu.Game.Screens.Select.FooterButtonRandom;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Navigation
|
||||
{
|
||||
@@ -274,6 +280,58 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
double getCarouselScrollPosition() => Game.ChildrenOfType<UserTrackingScrollContainer<DrawableCarouselItem>>().Single().Current;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNewSongSelectScrollHandling()
|
||||
{
|
||||
SoloSongSelect songSelect = null;
|
||||
double scrollPosition = 0;
|
||||
|
||||
AddStep("set game volume to max", () => Game.Dependencies.Get<FrameworkConfigManager>().SetValue(FrameworkSetting.VolumeUniversal, 1d));
|
||||
AddUntilStep("wait for volume overlay to hide", () => Game.ChildrenOfType<VolumeOverlay>().SingleOrDefault()?.State.Value, () => Is.EqualTo(Visibility.Hidden));
|
||||
PushAndConfirm(() => songSelect = new SoloSongSelect());
|
||||
AddUntilStep("wait for song select", () => songSelect.IsLoaded);
|
||||
AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).WaitSafely());
|
||||
AddUntilStep("wait for beatmap", () => Game.ChildrenOfType<PanelBeatmapSet>().Any());
|
||||
|
||||
AddWaitStep("wait for scroll", 10);
|
||||
|
||||
AddStep("store scroll position", () => scrollPosition = getCarouselScrollPosition());
|
||||
|
||||
AddStep("move to title wedge", () => InputManager.MoveMouseTo(
|
||||
songSelect.ChildrenOfType<BeatmapTitleWedge>().Single()));
|
||||
AddStep("scroll down", () => InputManager.ScrollVerticalBy(-1));
|
||||
AddAssert("carousel didn't move", getCarouselScrollPosition, () => Is.EqualTo(scrollPosition));
|
||||
|
||||
AddRepeatStep("alt-scroll down", () =>
|
||||
{
|
||||
InputManager.PressKey(Key.AltLeft);
|
||||
InputManager.ScrollVerticalBy(-1);
|
||||
InputManager.ReleaseKey(Key.AltLeft);
|
||||
}, 5);
|
||||
AddAssert("game volume decreased", () => Game.Dependencies.Get<FrameworkConfigManager>().Get<double>(FrameworkSetting.VolumeUniversal), () => Is.LessThan(1));
|
||||
|
||||
AddStep("set game volume to max", () => Game.Dependencies.Get<FrameworkConfigManager>().SetValue(FrameworkSetting.VolumeUniversal, 1d));
|
||||
|
||||
AddStep("move to metadata wedge", () => InputManager.MoveMouseTo(
|
||||
songSelect.ChildrenOfType<BeatmapMetadataWedge>().Single()));
|
||||
AddStep("scroll down", () => InputManager.ScrollVerticalBy(-1));
|
||||
AddAssert("carousel didn't move", getCarouselScrollPosition, () => Is.EqualTo(scrollPosition));
|
||||
|
||||
AddRepeatStep("alt-scroll down", () =>
|
||||
{
|
||||
InputManager.PressKey(Key.AltLeft);
|
||||
InputManager.ScrollVerticalBy(-1);
|
||||
InputManager.ReleaseKey(Key.AltLeft);
|
||||
}, 5);
|
||||
AddAssert("game volume decreased", () => Game.Dependencies.Get<FrameworkConfigManager>().Get<double>(FrameworkSetting.VolumeUniversal), () => Is.LessThan(1));
|
||||
|
||||
AddStep("move to carousel", () => InputManager.MoveMouseTo(songSelect.ChildrenOfType<Screens.SelectV2.BeatmapCarousel>().Single()));
|
||||
AddStep("scroll down", () => InputManager.ScrollVerticalBy(-1));
|
||||
AddAssert("carousel moved", getCarouselScrollPosition, () => Is.Not.EqualTo(scrollPosition));
|
||||
|
||||
double getCarouselScrollPosition() => Game.ChildrenOfType<Carousel<BeatmapInfo>>().Single().ChildrenOfType<UserTrackingScrollContainer>().Single().Current;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This tests that the F1 key will open the mod select overlay, and not be handled / blocked by the music controller (which has the same default binding
|
||||
/// but should be handled *after* song select).
|
||||
|
||||
@@ -136,6 +136,17 @@ namespace osu.Game.Graphics.Carousel
|
||||
selectionValid.Invalidate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scroll carousel to the selected item if available.
|
||||
/// </summary>
|
||||
public void ScrollToSelection()
|
||||
{
|
||||
// TODO: this likely needs to be delayed until currentKeyboardSelection has a valid value.
|
||||
// Early calls to `ScrollToSelection` will currently silently fail.
|
||||
if (currentKeyboardSelection.CarouselItem != null)
|
||||
Scroll.ScrollTo(currentKeyboardSelection.CarouselItem.CarouselYPosition - visibleHalfHeight + BleedTop);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the vertical spacing between two given carousel items. Negative value can be used to create an overlapping effect.
|
||||
/// </summary>
|
||||
@@ -316,7 +327,7 @@ namespace osu.Game.Graphics.Carousel
|
||||
|
||||
refreshAfterSelection();
|
||||
if (!Scroll.UserScrolling)
|
||||
scrollToSelection();
|
||||
ScrollToSelection();
|
||||
|
||||
NewItemsPresented?.Invoke(carouselItems);
|
||||
});
|
||||
@@ -553,12 +564,6 @@ namespace osu.Game.Graphics.Carousel
|
||||
Scroll.OffsetScrollPosition((float)(currentKeyboardSelection.YPosition!.Value - prevKeyboard.YPosition.Value));
|
||||
}
|
||||
|
||||
private void scrollToSelection()
|
||||
{
|
||||
if (currentKeyboardSelection.CarouselItem != null)
|
||||
Scroll.ScrollTo(currentKeyboardSelection.CarouselItem.CarouselYPosition - visibleHalfHeight + BleedTop);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Display handling
|
||||
@@ -598,7 +603,7 @@ namespace osu.Game.Graphics.Carousel
|
||||
refreshAfterSelection();
|
||||
|
||||
// Always scroll to selection in this case (regardless of `UserScrolling` state), centering the selection.
|
||||
scrollToSelection();
|
||||
ScrollToSelection();
|
||||
|
||||
selectionValid.Validate();
|
||||
}
|
||||
@@ -820,6 +825,11 @@ namespace osu.Game.Graphics.Carousel
|
||||
|
||||
public void SetLayoutHeight(float height) => Panels.Height = height;
|
||||
|
||||
/// <summary>
|
||||
/// Allow handling right click scroll outside of the carousel's display area.
|
||||
/// </summary>
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
|
||||
|
||||
public CarouselScrollContainer()
|
||||
{
|
||||
// Managing our own custom layout within ScrollContent causes feedback with public ScrollContainer calculations,
|
||||
|
||||
@@ -154,22 +154,43 @@ namespace osu.Game.Screens.SelectV2
|
||||
{
|
||||
new[]
|
||||
{
|
||||
wedgesContainer = new FillFlowContainer
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Margin = new MarginPadding
|
||||
{
|
||||
Top = -CORNER_RADIUS_HIDE_OFFSET,
|
||||
Left = -CORNER_RADIUS_HIDE_OFFSET
|
||||
},
|
||||
Spacing = new Vector2(0f, 4f),
|
||||
Direction = FillDirection.Vertical,
|
||||
// Ensure the left components are on top of the carousel both visually (although they should never overlay)
|
||||
// but more importantly, for input purposes to allow the scroll-to-selection logic to override carousel's
|
||||
// screen-wide scroll handling.
|
||||
Depth = float.MinValue,
|
||||
Shear = OsuGame.SHEAR,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new ShearAligningWrapper(titleWedge = new BeatmapTitleWedge()),
|
||||
new ShearAligningWrapper(detailsArea = new BeatmapDetailsArea()),
|
||||
},
|
||||
new Container
|
||||
{
|
||||
// Pad enough to only reset scroll when well into the left wedge areas.
|
||||
Padding = new MarginPadding { Right = 40 },
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = new Select.SongSelect.LeftSideInteractionContainer(() => carousel.ScrollToSelection())
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
},
|
||||
wedgesContainer = new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Margin = new MarginPadding
|
||||
{
|
||||
Top = -CORNER_RADIUS_HIDE_OFFSET,
|
||||
Left = -CORNER_RADIUS_HIDE_OFFSET
|
||||
},
|
||||
Spacing = new Vector2(0f, 4f),
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new ShearAligningWrapper(titleWedge = new BeatmapTitleWedge()),
|
||||
new ShearAligningWrapper(detailsArea = new BeatmapDetailsArea()),
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
Empty(),
|
||||
new Container
|
||||
|
||||
Reference in New Issue
Block a user