From 1f9a0927f45cd1951392da59ddf8535e4191f52c Mon Sep 17 00:00:00 2001 From: OliBomby Date: Wed, 16 Oct 2024 21:36:10 +0200 Subject: [PATCH 1/8] Allow slider bar to use keyboard input while not hovered --- osu.Framework/Graphics/UserInterface/SliderBar.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Framework/Graphics/UserInterface/SliderBar.cs b/osu.Framework/Graphics/UserInterface/SliderBar.cs index d1232baea4..df11dd97ae 100644 --- a/osu.Framework/Graphics/UserInterface/SliderBar.cs +++ b/osu.Framework/Graphics/UserInterface/SliderBar.cs @@ -172,14 +172,13 @@ protected override bool OnDragStart(DragStartEvent e) protected override void OnDragEnd(DragEndEvent e) => Commit(); + public override bool AcceptsFocus => true; + protected override bool OnKeyDown(KeyDownEvent e) { if (currentNumberInstantaneous.Disabled) return false; - if (!IsHovered) - return false; - float step = KeyboardStep != 0 ? KeyboardStep : (Convert.ToSingle(currentNumberInstantaneous.MaxValue) - Convert.ToSingle(currentNumberInstantaneous.MinValue)) / 20; if (currentNumberInstantaneous.IsInteger) step = MathF.Ceiling(step); From c088bdb6979d3bfbcd4d17cb0a8178e6e1981954 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Thu, 17 Oct 2024 23:56:07 +0200 Subject: [PATCH 2/8] Require either hover or focus for keyboard input --- osu.Framework/Graphics/UserInterface/SliderBar.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Framework/Graphics/UserInterface/SliderBar.cs b/osu.Framework/Graphics/UserInterface/SliderBar.cs index df11dd97ae..2a605d4a2c 100644 --- a/osu.Framework/Graphics/UserInterface/SliderBar.cs +++ b/osu.Framework/Graphics/UserInterface/SliderBar.cs @@ -179,6 +179,9 @@ protected override bool OnKeyDown(KeyDownEvent e) if (currentNumberInstantaneous.Disabled) return false; + if (!IsHovered && !HasFocus) + return false; + float step = KeyboardStep != 0 ? KeyboardStep : (Convert.ToSingle(currentNumberInstantaneous.MaxValue) - Convert.ToSingle(currentNumberInstantaneous.MinValue)) / 20; if (currentNumberInstantaneous.IsInteger) step = MathF.Ceiling(step); From c5897612d4762a2757cb3030ac9755f6e6806017 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Thu, 17 Oct 2024 23:56:24 +0200 Subject: [PATCH 3/8] update test --- .../Visual/UserInterface/TestSceneSliderBar.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/osu.Framework.Tests/Visual/UserInterface/TestSceneSliderBar.cs b/osu.Framework.Tests/Visual/UserInterface/TestSceneSliderBar.cs index d41832481c..ad8410fc17 100644 --- a/osu.Framework.Tests/Visual/UserInterface/TestSceneSliderBar.cs +++ b/osu.Framework.Tests/Visual/UserInterface/TestSceneSliderBar.cs @@ -160,6 +160,20 @@ public void TestKeyboardInput() InputManager.ReleaseKey(Key.Right); }); checkValue(1); + + AddStep("Focus slider", () => GetContainingFocusManager().ChangeFocus(sliderBar)); + + AddStep("move mouse outside", () => + { + InputManager.MoveMouseTo(sliderBar.ToScreenSpace(sliderBar.DrawSize * new Vector2(2f, 0.5f))); + }); + + AddStep("Press right arrow key", () => + { + InputManager.PressKey(Key.Right); + InputManager.ReleaseKey(Key.Right); + }); + checkValue(2); } [TestCase(false)] From 6639515fd687d9ff7f0dcfd67dcf30745e57a8bc Mon Sep 17 00:00:00 2001 From: OliBomby Date: Fri, 18 Oct 2024 00:56:06 +0200 Subject: [PATCH 4/8] fix test failing when run in batch --- .../Visual/UserInterface/TestSceneSliderBar.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Framework.Tests/Visual/UserInterface/TestSceneSliderBar.cs b/osu.Framework.Tests/Visual/UserInterface/TestSceneSliderBar.cs index ad8410fc17..f3bd8079ba 100644 --- a/osu.Framework.Tests/Visual/UserInterface/TestSceneSliderBar.cs +++ b/osu.Framework.Tests/Visual/UserInterface/TestSceneSliderBar.cs @@ -141,6 +141,8 @@ public void TestDragOutReleaseInHasNoEffect() [Test] public void TestKeyboardInput() { + AddStep("Unfocus slider", () => sliderBar.GetContainingFocusManager()!.ChangeFocus(null)); + AddStep("Press right arrow key", () => { InputManager.PressKey(Key.Right); @@ -161,7 +163,7 @@ public void TestKeyboardInput() }); checkValue(1); - AddStep("Focus slider", () => GetContainingFocusManager().ChangeFocus(sliderBar)); + AddStep("Focus slider", () => sliderBar.GetContainingFocusManager()!.ChangeFocus(sliderBar)); AddStep("move mouse outside", () => { From ffa30d8e158b94d2136492e2dc5342f0c591d15f Mon Sep 17 00:00:00 2001 From: OliBomby Date: Fri, 18 Oct 2024 01:07:28 +0200 Subject: [PATCH 5/8] Add focus feedback to BasicSliderBar --- .../UserInterface/TestSceneSliderBar.cs | 4 ++ .../Graphics/UserInterface/BasicSliderBar.cs | 43 +++++++++++++++++-- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/osu.Framework.Tests/Visual/UserInterface/TestSceneSliderBar.cs b/osu.Framework.Tests/Visual/UserInterface/TestSceneSliderBar.cs index f3bd8079ba..c22e31cdf9 100644 --- a/osu.Framework.Tests/Visual/UserInterface/TestSceneSliderBar.cs +++ b/osu.Framework.Tests/Visual/UserInterface/TestSceneSliderBar.cs @@ -59,6 +59,7 @@ public TestSceneSliderBar() Size = new Vector2(200, 50), BackgroundColour = Color4.White, SelectionColour = Color4.Pink, + FocusColour = Color4.Purple, KeyboardStep = 1, Current = sliderBarValue }, @@ -72,6 +73,7 @@ public TestSceneSliderBar() RangePadding = 20, BackgroundColour = Color4.White, SelectionColour = Color4.Pink, + FocusColour = Color4.Purple, KeyboardStep = 1, Current = sliderBarValue }, @@ -85,6 +87,7 @@ public TestSceneSliderBar() Size = new Vector2(200, 10), BackgroundColour = Color4.White, SelectionColour = Color4.Pink, + FocusColour = Color4.Purple, KeyboardStep = 1, Current = sliderBarValue }, @@ -97,6 +100,7 @@ public TestSceneSliderBar() Size = new Vector2(200, 10), BackgroundColour = Color4.White, SelectionColour = Color4.Pink, + FocusColour = Color4.Purple, KeyboardStep = 1, Current = sliderBarValue }, diff --git a/osu.Framework/Graphics/UserInterface/BasicSliderBar.cs b/osu.Framework/Graphics/UserInterface/BasicSliderBar.cs index 17b932cee9..eac74881fb 100644 --- a/osu.Framework/Graphics/UserInterface/BasicSliderBar.cs +++ b/osu.Framework/Graphics/UserInterface/BasicSliderBar.cs @@ -4,6 +4,7 @@ using System.Numerics; using osuTK.Graphics; using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Events; using Vector2 = osuTK.Vector2; namespace osu.Framework.Graphics.UserInterface @@ -17,10 +18,28 @@ public Color4 BackgroundColour set => Box.Colour = value; } + private Color4 selectionColour = FrameworkColour.Yellow; + public Color4 SelectionColour { - get => SelectionBox.Colour; - set => SelectionBox.Colour = value; + get => selectionColour; + set + { + selectionColour = value; + updateColour(); + } + } + + private Color4 focusColour = FrameworkColour.YellowGreen; + + public Color4 FocusColour + { + get => focusColour; + set + { + focusColour = value; + updateColour(); + } } protected readonly Box SelectionBox; @@ -38,9 +57,27 @@ public BasicSliderBar() SelectionBox = new Box { RelativeSizeAxes = Axes.Both, - Colour = FrameworkColour.Yellow, } }; + + updateColour(); + } + + private void updateColour() + { + SelectionBox.Colour = HasFocus ? FocusColour : SelectionColour; + } + + protected override void OnFocus(FocusEvent e) + { + updateColour(); + base.OnFocus(e); + } + + protected override void OnFocusLost(FocusLostEvent e) + { + updateColour(); + base.OnFocusLost(e); } protected override void UpdateValue(float value) From 5d55636912c79a2a0c1f0341a67e4819f8093b7c Mon Sep 17 00:00:00 2001 From: OliBomby Date: Sat, 19 Oct 2024 22:49:34 +0200 Subject: [PATCH 6/8] sliderbar takes focus on successful drag --- .../Visual/UserInterface/TestSceneSliderBar.cs | 8 ++++++-- osu.Framework/Graphics/UserInterface/SliderBar.cs | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/osu.Framework.Tests/Visual/UserInterface/TestSceneSliderBar.cs b/osu.Framework.Tests/Visual/UserInterface/TestSceneSliderBar.cs index c22e31cdf9..797cba1c4d 100644 --- a/osu.Framework.Tests/Visual/UserInterface/TestSceneSliderBar.cs +++ b/osu.Framework.Tests/Visual/UserInterface/TestSceneSliderBar.cs @@ -113,6 +113,8 @@ public TestSceneSliderBar() { sliderBar.Current.Disabled = false; sliderBar.Current.Value = 0; + sliderBar.GetContainingFocusManager()!.ChangeFocus(null); + sliderBarWithNub.GetContainingFocusManager()!.ChangeFocus(null); }); [Test] @@ -126,6 +128,7 @@ public void TestVerticalDragHasNoEffect() () => { InputManager.MoveMouseTo(sliderBar.ToScreenSpace(sliderBar.DrawSize * new Vector2(0.75f, 1f))); }); AddStep("Release Click", () => { InputManager.ReleaseButton(MouseButton.Left); }); checkValue(0); + AddAssert("Slider has no focus", () => !sliderBar.HasFocus); } [Test] @@ -140,13 +143,12 @@ public void TestDragOutReleaseInHasNoEffect() AddStep("Drag Up", () => { InputManager.MoveMouseTo(sliderBar.ToScreenSpace(sliderBar.DrawSize * new Vector2(0.25f, 0.5f))); }); AddStep("Release Click", () => { InputManager.ReleaseButton(MouseButton.Left); }); checkValue(0); + AddAssert("Slider has focus", () => sliderBar.HasFocus); } [Test] public void TestKeyboardInput() { - AddStep("Unfocus slider", () => sliderBar.GetContainingFocusManager()!.ChangeFocus(null)); - AddStep("Press right arrow key", () => { InputManager.PressKey(Key.Right); @@ -266,6 +268,7 @@ public void TestAbsoluteDrag() () => { InputManager.MoveMouseTo(sliderBarWithNub.ToScreenSpace(sliderBarWithNub.DrawSize * new Vector2(0.4f, 1f))); }); AddStep("Release Click", () => { InputManager.ReleaseButton(MouseButton.Left); }); checkValue(-2); + AddAssert("Slider has focus", () => sliderBarWithNub.HasFocus); } [Test] @@ -279,6 +282,7 @@ public void TestRelativeDrag() () => { InputManager.MoveMouseTo(sliderBarWithNub.ToScreenSpace(sliderBarWithNub.DrawSize * new Vector2(0.75f, 1f))); }); AddStep("Release Click", () => { InputManager.ReleaseButton(MouseButton.Left); }); checkValue(3); + AddAssert("Slider has focus", () => sliderBarWithNub.HasFocus); } [Test] diff --git a/osu.Framework/Graphics/UserInterface/SliderBar.cs b/osu.Framework/Graphics/UserInterface/SliderBar.cs index 2a605d4a2c..20fe6a18b7 100644 --- a/osu.Framework/Graphics/UserInterface/SliderBar.cs +++ b/osu.Framework/Graphics/UserInterface/SliderBar.cs @@ -166,6 +166,7 @@ protected override bool OnDragStart(DragStartEvent e) return false; } + GetContainingFocusManager()?.ChangeFocus(this); handleMouseInput(e); return true; } From df5fffcfbb54b4910817ad70e6f0c331f3a37dec Mon Sep 17 00:00:00 2001 From: OliBomby Date: Sun, 20 Oct 2024 15:20:37 +0200 Subject: [PATCH 7/8] test focus using click instead of programmed focus --- .../Visual/UserInterface/TestSceneSliderBar.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Framework.Tests/Visual/UserInterface/TestSceneSliderBar.cs b/osu.Framework.Tests/Visual/UserInterface/TestSceneSliderBar.cs index 797cba1c4d..3ebcd0482f 100644 --- a/osu.Framework.Tests/Visual/UserInterface/TestSceneSliderBar.cs +++ b/osu.Framework.Tests/Visual/UserInterface/TestSceneSliderBar.cs @@ -169,7 +169,10 @@ public void TestKeyboardInput() }); checkValue(1); - AddStep("Focus slider", () => sliderBar.GetContainingFocusManager()!.ChangeFocus(sliderBar)); + AddStep("Click slider", () => InputManager.Click(MouseButton.Left)); + checkValue(-5); + + AddAssert("Slider has focus", () => sliderBar.HasFocus); AddStep("move mouse outside", () => { @@ -181,7 +184,7 @@ public void TestKeyboardInput() InputManager.PressKey(Key.Right); InputManager.ReleaseKey(Key.Right); }); - checkValue(2); + checkValue(-4); } [TestCase(false)] From cc00127bf52481320742663f9adecd99ce37add5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Oct 2024 15:46:55 +0900 Subject: [PATCH 8/8] Improve visuals of `BasicSliderBar` focus --- .../UserInterface/TestSceneSliderBar.cs | 8 ++-- .../Graphics/UserInterface/BasicSliderBar.cs | 37 ++++++++++--------- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/osu.Framework.Tests/Visual/UserInterface/TestSceneSliderBar.cs b/osu.Framework.Tests/Visual/UserInterface/TestSceneSliderBar.cs index 3ebcd0482f..9cf6f699c3 100644 --- a/osu.Framework.Tests/Visual/UserInterface/TestSceneSliderBar.cs +++ b/osu.Framework.Tests/Visual/UserInterface/TestSceneSliderBar.cs @@ -59,7 +59,7 @@ public TestSceneSliderBar() Size = new Vector2(200, 50), BackgroundColour = Color4.White, SelectionColour = Color4.Pink, - FocusColour = Color4.Purple, + FocusColour = Color4.OrangeRed, KeyboardStep = 1, Current = sliderBarValue }, @@ -73,7 +73,7 @@ public TestSceneSliderBar() RangePadding = 20, BackgroundColour = Color4.White, SelectionColour = Color4.Pink, - FocusColour = Color4.Purple, + FocusColour = Color4.OrangeRed, KeyboardStep = 1, Current = sliderBarValue }, @@ -87,7 +87,7 @@ public TestSceneSliderBar() Size = new Vector2(200, 10), BackgroundColour = Color4.White, SelectionColour = Color4.Pink, - FocusColour = Color4.Purple, + FocusColour = Color4.OrangeRed, KeyboardStep = 1, Current = sliderBarValue }, @@ -100,7 +100,7 @@ public TestSceneSliderBar() Size = new Vector2(200, 10), BackgroundColour = Color4.White, SelectionColour = Color4.Pink, - FocusColour = Color4.Purple, + FocusColour = Color4.OrangeRed, KeyboardStep = 1, Current = sliderBarValue }, diff --git a/osu.Framework/Graphics/UserInterface/BasicSliderBar.cs b/osu.Framework/Graphics/UserInterface/BasicSliderBar.cs index eac74881fb..9b6697d13d 100644 --- a/osu.Framework/Graphics/UserInterface/BasicSliderBar.cs +++ b/osu.Framework/Graphics/UserInterface/BasicSliderBar.cs @@ -18,16 +18,10 @@ public Color4 BackgroundColour set => Box.Colour = value; } - private Color4 selectionColour = FrameworkColour.Yellow; - public Color4 SelectionColour { - get => selectionColour; - set - { - selectionColour = value; - updateColour(); - } + get => SelectionBox.Colour; + set => SelectionBox.Colour = value; } private Color4 focusColour = FrameworkColour.YellowGreen; @@ -38,7 +32,7 @@ public Color4 FocusColour set { focusColour = value; - updateColour(); + updateFocus(); } } @@ -56,30 +50,39 @@ public BasicSliderBar() }, SelectionBox = new Box { + Colour = FrameworkColour.Yellow, RelativeSizeAxes = Axes.Both, } }; - updateColour(); - } - - private void updateColour() - { - SelectionBox.Colour = HasFocus ? FocusColour : SelectionColour; + Masking = true; } protected override void OnFocus(FocusEvent e) { - updateColour(); + updateFocus(); base.OnFocus(e); } protected override void OnFocusLost(FocusLostEvent e) { - updateColour(); + updateFocus(); base.OnFocusLost(e); } + private void updateFocus() + { + if (HasFocus) + { + BorderThickness = 3; + BorderColour = FocusColour; + } + else + { + BorderThickness = 0; + } + } + protected override void UpdateValue(float value) { SelectionBox.ScaleTo(new Vector2(value, 1), 300, Easing.OutQuint);