From 9d88c761d3414d3e4353bd0a66f2faac2630c83e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 24 Nov 2025 10:32:42 +0100 Subject: [PATCH] Add double-click-nub-to-reset function to form slider bars See https://github.com/ppy/osu/pull/35742#issuecomment-3561517030. --- .../UserInterface/TestSceneFormSliderBar.cs | 50 ++++++++++++++++++- .../Graphics/UserInterfaceV2/FormSliderBar.cs | 39 ++++++++++++--- 2 files changed, 80 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFormSliderBar.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFormSliderBar.cs index 97835a993d..d25ef3a889 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFormSliderBar.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFormSliderBar.cs @@ -1,20 +1,24 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Testing; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Overlays; using osuTK; +using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { - public partial class TestSceneFormSliderBar : OsuTestScene + public partial class TestSceneFormSliderBar : OsuManualInputManagerTestScene { [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Aquamarine); @@ -59,5 +63,49 @@ namespace osu.Game.Tests.Visual.UserInterface slider.TransferValueOnCommit = b; }); } + + [Test] + public void TestNubDoubleClickRevertToDefault() + { + FormSliderBar slider = null!; + + AddStep("create content", () => + { + Child = new FillFlowContainer + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Width = 0.5f, + Direction = FillDirection.Vertical, + Spacing = new Vector2(10), + Children = new Drawable[] + { + slider = new FormSliderBar + { + Caption = "Slider", + Current = new BindableFloat + { + MinValue = 0, + MaxValue = 10, + Precision = 0.1f, + Default = 5f, + } + }, + } + }; + }); + AddStep("set slider to 1", () => slider.Current.Value = 1); + + AddStep("move mouse to nub", () => InputManager.MoveMouseTo(slider.ChildrenOfType().Single())); + + AddStep("double click nub", () => + { + InputManager.Click(MouseButton.Left); + InputManager.Click(MouseButton.Left); + }); + + AddAssert("slider is default", () => slider.Current.IsDefault); + } } } diff --git a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs index 59217f64ab..8ebaf48ed6 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs @@ -324,8 +324,8 @@ namespace osu.Game.Graphics.UserInterfaceV2 private Box leftBox = null!; private Box rightBox = null!; - private Circle nub = null!; - private const float nub_width = 10; + private InnerSliderNub nub = null!; + public const float NUB_WIDTH = 10; [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; @@ -335,7 +335,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 { Height = 40; RelativeSizeAxes = Axes.X; - RangePadding = nub_width / 2; + RangePadding = NUB_WIDTH / 2; Children = new Drawable[] { @@ -364,12 +364,13 @@ namespace osu.Game.Graphics.UserInterfaceV2 { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Horizontal = RangePadding, }, - Child = nub = new Circle + Child = nub = new InnerSliderNub { - Width = nub_width, - RelativeSizeAxes = Axes.Y, - RelativePositionAxes = Axes.X, - Origin = Anchor.TopCentre, + ResetToDefault = () => + { + if (!Current.Disabled) + Current.SetDefault(); + } } }, new HoverClickSounds() @@ -452,5 +453,27 @@ namespace osu.Game.Graphics.UserInterfaceV2 return result; } } + + private partial class InnerSliderNub : Circle + { + public Action? ResetToDefault { get; set; } + + [BackgroundDependencyLoader] + private void load() + { + Width = InnerSlider.NUB_WIDTH; + RelativeSizeAxes = Axes.Y; + RelativePositionAxes = Axes.X; + Origin = Anchor.TopCentre; + } + + protected override bool OnClick(ClickEvent e) => true; // must be handled for double click handler to ever fire + + protected override bool OnDoubleClick(DoubleClickEvent e) + { + ResetToDefault?.Invoke(); + return true; + } + } } }