diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFormControls.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFormControls.cs index 2003f5de83..a1872b30de 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFormControls.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFormControls.cs @@ -1,15 +1,18 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Shapes; using osu.Game.Beatmaps; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Cursor; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; +using osu.Game.Overlays; using osu.Game.Screens.Edit.Setup; using osuTK; @@ -25,109 +28,199 @@ namespace osu.Game.Tests.Visual.UserInterface protected override Drawable CreateContent() => new OsuContextMenuContainer { RelativeSizeAxes = Axes.Both, - Child = new PopoverContainer + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Child = new OsuScrollContainer + new BackgroundBox { RelativeSizeAxes = Axes.Both, - Child = new FillFlowContainer + }, + new PopoverContainer + { + RelativeSizeAxes = Axes.Both, + Child = new OsuScrollContainer { - AutoSizeAxes = Axes.Y, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Width = 400, - Direction = FillDirection.Vertical, - Spacing = new Vector2(5), - Padding = new MarginPadding(10), - Children = new Drawable[] + RelativeSizeAxes = Axes.Both, + Child = new FillFlowContainer { - new FormTextBox + AutoSizeAxes = Axes.Y, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Width = 400, + Direction = FillDirection.Vertical, + Spacing = new Vector2(5), + Padding = new MarginPadding(10), + Children = new Drawable[] { - Caption = "Artist", - HintText = "Poot artist here!", - PlaceholderText = "Here is an artist", - TabbableContentContainer = this, - }, - new FormTextBox - { - Caption = "Artist", - HintText = "Poot artist here!", - PlaceholderText = "Here is an artist", - Current = { Disabled = true }, - TabbableContentContainer = this, - }, - new FormNumberBox(allowDecimals: true) - { - Caption = "Number", - HintText = "Insert your favourite number", - PlaceholderText = "Mine is 42!", - TabbableContentContainer = this, - }, - new FormCheckBox - { - Caption = EditorSetupStrings.LetterboxDuringBreaks, - HintText = EditorSetupStrings.LetterboxDuringBreaksDescription, - }, - new FormCheckBox - { - Caption = EditorSetupStrings.LetterboxDuringBreaks, - HintText = EditorSetupStrings.LetterboxDuringBreaksDescription, - Current = { Disabled = true }, - }, - new FormSliderBar - { - Caption = "Slider", - Current = new BindableFloat + new FormTextBox { - MinValue = 0, - MaxValue = 10, - Value = 5, - Precision = 0.1f, + Caption = "Artist", + HintText = "Poot artist here!", + PlaceholderText = "Here is an artist", + TabbableContentContainer = this, }, - TabbableContentContainer = this, - }, - new FormEnumDropdown - { - Caption = EditorSetupStrings.EnableCountdown, - HintText = EditorSetupStrings.CountdownDescription, - }, - new FormFileSelector - { - Caption = "File selector", - PlaceholderText = "Select a file", - }, - new FormBeatmapFileSelector(true) - { - Caption = "File selector with intermediate choice dialog", - PlaceholderText = "Select a file", - }, - new FormColourPalette - { - Caption = "Combo colours", - Colours = + new FormTextBox { - Colour4.Red, - Colour4.Green, - Colour4.Blue, - Colour4.Yellow, - } - }, - new FormButton - { - Caption = "No text in button", - Action = () => { }, - }, - new FormButton - { - Caption = "Text in button which is pretty long and is very likely to wrap", - ButtonText = "Foo the bar", - Action = () => { }, + Caption = "Artist", + HintText = "Poot artist here!", + PlaceholderText = "Here is an artist", + Current = { Disabled = true }, + TabbableContentContainer = this, + }, + new FormNumberBox(allowDecimals: true) + { + Caption = "Number", + HintText = "Insert your favourite number", + PlaceholderText = "Mine is 42!", + TabbableContentContainer = this, + }, + new FormCheckBox + { + Caption = EditorSetupStrings.LetterboxDuringBreaks, + HintText = EditorSetupStrings.LetterboxDuringBreaksDescription, + }, + new FormCheckBox + { + Caption = EditorSetupStrings.LetterboxDuringBreaks, + HintText = EditorSetupStrings.LetterboxDuringBreaksDescription, + Current = { Disabled = true }, + }, + new FormCheckBox + { + Caption = EditorSetupStrings.LetterboxDuringBreaks, + HintText = EditorSetupStrings.LetterboxDuringBreaksDescription, + Current = { Value = true, Disabled = true }, + }, + new FormSliderBar + { + Caption = "Slider", + HintText = "Slider hint", + Current = new BindableFloat + { + MinValue = 0, + MaxValue = 10, + Value = 5, + Precision = 0.1f, + }, + TabbableContentContainer = this, + }, + new FormSliderBar + { + Caption = "Slider", + HintText = "Slider hint", + Current = new BindableFloat + { + MinValue = 0, + MaxValue = 10, + Value = 5, + Precision = 0.1f, + Disabled = true, + }, + TransferValueOnCommit = true, + TabbableContentContainer = this, + }, + new FormSliderBar + { + Caption = "Slider (percentage)", + HintText = "Percentage slider hint", + Current = new BindableFloat + { + MinValue = 0, + MaxValue = 1, + Value = 0.2f, + Precision = 0.0001f, + }, + DisplayAsPercentage = true, + TabbableContentContainer = this, + }, + new FormSliderBar + { + Caption = "Slider (custom)", + HintText = "Custom slider hint", + Current = new BindableFloat + { + MinValue = 0, + MaxValue = 1, + Value = 0.2f, + Precision = 0.0001f, + }, + LabelFormat = v => $"{v * 100:0.00} funometer", + TooltipFormat = v => $"This setting has the value set to {v * 100:0.00} funometer.", + TabbableContentContainer = this, + }, + new FormSliderBar + { + Caption = "Slider (custom)", + HintText = "Custom slider hint", + Current = new BindableFloat + { + MinValue = 0, + MaxValue = 1, + Value = 0.2f, + Precision = 0.0001f, + Disabled = true, + }, + TransferValueOnCommit = true, + LabelFormat = v => $"{v * 100:0.00} funometer", + TooltipFormat = v => $"This setting has the value set to {v * 100:0.00} funometer.", + TabbableContentContainer = this, + }, + new FormEnumDropdown + { + Caption = EditorSetupStrings.EnableCountdown, + HintText = EditorSetupStrings.CountdownDescription, + }, + new FormEnumDropdown + { + Caption = EditorSetupStrings.EnableCountdown, + HintText = EditorSetupStrings.CountdownDescription, + Current = { Disabled = true }, + }, + new FormFileSelector + { + Caption = "File selector", + PlaceholderText = "Select a file", + }, + new FormBeatmapFileSelector(true) + { + Caption = "File selector with intermediate choice dialog", + PlaceholderText = "Select a file", + }, + new FormColourPalette + { + Caption = "Combo colours", + Colours = + { + Colour4.Red, + Colour4.Green, + Colour4.Blue, + Colour4.Yellow, + } + }, + new FormButton + { + Caption = "No text in button", + Action = () => { }, + }, + new FormButton + { + Caption = "Text in button which is pretty long and is very likely to wrap", + ButtonText = "Foo the bar", + Action = () => { }, + }, }, }, }, - }, + } } }; + + private partial class BackgroundBox : Box + { + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + Colour = colourProvider.Background4; + } + } } } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledSwitchButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledSwitchButton.cs index bec517af2c..24ef51806a 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledSwitchButton.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledSwitchButton.cs @@ -2,14 +2,19 @@ // See the LICENCE file in the repository root for full licence text. using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Overlays; namespace osu.Game.Tests.Visual.UserInterface { public partial class TestSceneLabelledSwitchButton : OsuTestScene { + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink); + [TestCase(false)] [TestCase(true)] public void TestSwitchButton(bool hasDescription) => createSwitchButton(hasDescription); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneSwitchButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneSwitchButton.cs index f3ab5dbff8..9b2a7ae2ef 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneSwitchButton.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneSwitchButton.cs @@ -4,15 +4,21 @@ #nullable disable using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Overlays; using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { public partial class TestSceneSwitchButton : OsuManualInputManagerTestScene { + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink); + private SwitchButton switchButton; [SetUp] @@ -42,5 +48,15 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("toggle bindable", () => bindable.Toggle()); AddStep("toggle bindable", () => bindable.Toggle()); } + + [Test] + public void TestDisabledState() + { + AddToggleStep("toggle disabled", v => + { + if (switchButton.IsNotNull()) + switchButton.Current.Disabled = v; + }); + } } } diff --git a/osu.Game.Tournament/Screens/Setup/SetupScreen.cs b/osu.Game.Tournament/Screens/Setup/SetupScreen.cs index bd368d88a0..6bed3c87df 100644 --- a/osu.Game.Tournament/Screens/Setup/SetupScreen.cs +++ b/osu.Game.Tournament/Screens/Setup/SetupScreen.cs @@ -8,7 +8,6 @@ using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Online.API; @@ -56,7 +55,7 @@ namespace osu.Game.Tournament.Screens.Setup new Box { RelativeSizeAxes = Axes.Both, - Colour = OsuColour.Gray(0.2f), + Colour = ColourProvider.Background5, }, new OsuScrollContainer { diff --git a/osu.Game.Tournament/Screens/TournamentScreen.cs b/osu.Game.Tournament/Screens/TournamentScreen.cs index 1e119e0336..137153b91d 100644 --- a/osu.Game.Tournament/Screens/TournamentScreen.cs +++ b/osu.Game.Tournament/Screens/TournamentScreen.cs @@ -4,6 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Overlays; using osu.Game.Tournament.Models; namespace osu.Game.Tournament.Screens @@ -15,6 +16,9 @@ namespace osu.Game.Tournament.Screens [Resolved] protected LadderInfo LadderInfo { get; private set; } = null!; + [Cached] + protected readonly OverlayColourProvider ColourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); + protected TournamentScreen() { RelativeSizeAxes = Axes.Both; diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs index ca95d45042..72e3b19a6a 100644 --- a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs @@ -25,12 +25,12 @@ namespace osu.Game.Graphics.UserInterface /// public bool DisplayAsPercentage { get; set; } - public virtual LocalisableString TooltipText { get; private set; } + public virtual LocalisableString TooltipText { get; protected set; } /// /// Maximum number of decimal digits to be displayed in the tooltip. /// - private const int max_decimal_digits = 5; + public const int MAX_DECIMAL_DIGITS = 5; private Sample sample = null!; @@ -46,7 +46,7 @@ namespace osu.Game.Graphics.UserInterface protected override void LoadComplete() { base.LoadComplete(); - CurrentNumber.BindValueChanged(current => TooltipText = GetDisplayableValue(current.NewValue), true); + CurrentNumber.BindValueChanged(current => TooltipText = GetTooltipText(current.NewValue), true); } protected override void OnUserChange(T value) @@ -55,7 +55,7 @@ namespace osu.Game.Graphics.UserInterface playSample(value); - TooltipText = GetDisplayableValue(value); + TooltipText = GetTooltipText(value); } private void playSample(T value) @@ -83,6 +83,6 @@ namespace osu.Game.Graphics.UserInterface channel.Play(); } - public LocalisableString GetDisplayableValue(T value) => value.ToStandardFormattedString(max_decimal_digits, DisplayAsPercentage); + protected virtual LocalisableString GetTooltipText(T value) => value.ToStandardFormattedString(MAX_DECIMAL_DIGITS, DisplayAsPercentage); } } diff --git a/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs b/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs index 586f6546ab..f54cc7cc7c 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormCheckBox.cs @@ -16,7 +16,6 @@ using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Framework.Localisation; using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; using osu.Game.Overlays; @@ -45,10 +44,10 @@ namespace osu.Game.Graphics.UserInterfaceV2 private Box background = null!; private FormFieldCaption caption = null!; private OsuSpriteText text = null!; - private Nub checkbox = null!; private Sample? sampleChecked; private Sample? sampleUnchecked; + private Sample? sampleDisabled; [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; @@ -89,7 +88,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, }, - checkbox = new Nub + new SwitchButton { Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, @@ -101,6 +100,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 sampleChecked = audio.Samples.Get(@"UI/check-on"); sampleUnchecked = audio.Samples.Get(@"UI/check-off"); + sampleDisabled = audio.Samples.Get(@"UI/default-select-disabled"); } protected override void LoadComplete() @@ -142,25 +142,26 @@ namespace osu.Game.Graphics.UserInterfaceV2 { if (!Current.Disabled) Current.Value = !Current.Value; + else + sampleDisabled?.Play(); + return true; } private void updateState() { - background.Colour = Current.Disabled ? colourProvider.Background4 : colourProvider.Background5; - caption.Colour = Current.Disabled ? colourProvider.Foreground1 : colourProvider.Content2; - checkbox.Colour = Current.Disabled ? colourProvider.Foreground1 : colourProvider.Content1; - text.Colour = Current.Disabled ? colourProvider.Foreground1 : colourProvider.Content1; + caption.Colour = Current.Disabled ? colourProvider.Background1 : colourProvider.Content2; + text.Colour = Current.Disabled ? colourProvider.Background1 : colourProvider.Content1; text.Text = Current.Value ? CommonStrings.Enabled : CommonStrings.Disabled; - if (!Current.Disabled) - { - BorderThickness = IsHovered ? 2 : 0; + // use FadeColour to override any existing colour transform (i.e. FlashColour on click). + background.FadeColour(IsHovered + ? ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark4) + : colourProvider.Background5); - if (IsHovered) - BorderColour = colourProvider.Light4; - } + BorderThickness = IsHovered ? 2 : 0; + BorderColour = Current.Disabled ? colourProvider.Dark1 : colourProvider.Light4; } public IEnumerable FilterTerms => Caption.Yield(); diff --git a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs index a12d166f56..1c595e1386 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs @@ -171,10 +171,14 @@ namespace osu.Game.Graphics.UserInterfaceV2 Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, Size = new Vector2(16), + Margin = new MarginPadding { Right = 5 }, }, }; - AddInternal(new HoverClickSounds()); + AddInternal(new HoverClickSounds + { + Enabled = { BindTarget = Enabled }, + }); } protected override void LoadComplete() @@ -210,29 +214,26 @@ namespace osu.Game.Graphics.UserInterfaceV2 { label.Alpha = string.IsNullOrEmpty(SearchBar.SearchTerm.Value) ? 1 : 0; - caption.Colour = Dropdown.Current.Disabled ? colourProvider.Foreground1 : colourProvider.Content2; - label.Colour = Dropdown.Current.Disabled ? colourProvider.Foreground1 : colourProvider.Content1; - chevron.Colour = Dropdown.Current.Disabled ? colourProvider.Foreground1 : colourProvider.Content1; + caption.Colour = Dropdown.Current.Disabled ? colourProvider.Background1 : colourProvider.Content2; + label.Colour = Dropdown.Current.Disabled ? colourProvider.Background1 : colourProvider.Content1; + chevron.Colour = Dropdown.Current.Disabled ? colourProvider.Background1 : colourProvider.Content1; DisabledColour = Colour4.White; bool dropdownOpen = Dropdown.Menu.State == MenuState.Open; - if (!Dropdown.Current.Disabled) - { - BorderThickness = IsHovered || dropdownOpen ? 2 : 0; + BorderThickness = IsHovered || dropdownOpen ? 2 : 0; + + if (Dropdown.Current.Disabled) + BorderColour = colourProvider.Dark1; + else BorderColour = dropdownOpen ? colourProvider.Highlight1 : colourProvider.Light4; - if (dropdownOpen) - Background.Colour = ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark3); - else if (IsHovered) - Background.Colour = ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark4); - else - Background.Colour = colourProvider.Background5; - } + if (dropdownOpen) + Background.Colour = ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark3); + else if (IsHovered) + Background.Colour = ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark4); else - { - Background.Colour = colourProvider.Background4; - } + Background.Colour = colourProvider.Background5; } private void updateChevron() diff --git a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs index 06f9db7846..310be77f31 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs @@ -17,6 +17,8 @@ using osu.Framework.Graphics.UserInterface; using osu.Framework.Input; using osu.Framework.Input.Events; using osu.Framework.Localisation; +using osu.Game.Extensions; +using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; using osu.Game.Overlays; @@ -97,9 +99,31 @@ namespace osu.Game.Graphics.UserInterfaceV2 } } + /// + /// Whether to format the tooltip as a percentage or the actual value. + /// + public bool DisplayAsPercentage { get; init; } + + /// + /// Whether sound effects should play when adjusting this slider. + /// + public bool PlaySamplesOnAdjust { get; init; } + + /// + /// The string formatting function to use for the value label. + /// + public Func LabelFormat { get; init; } + + /// + /// The string formatting function to use for the slider's tooltip text. + /// If not provided, is used. + /// + public Func TooltipFormat { get; init; } + private Box background = null!; private Box flashLayer = null!; private FormTextBox.InnerTextBox textBox = null!; + private OsuSpriteText valueLabel = null!; private InnerSlider slider = null!; private FormFieldCaption captionText = null!; private IFocusManager focusManager = null!; @@ -109,6 +133,12 @@ namespace osu.Game.Graphics.UserInterfaceV2 private readonly Bindable currentLanguage = new Bindable(); + public FormSliderBar() + { + LabelFormat ??= defaultLabelFormat; + TooltipFormat ??= v => LabelFormat(v); + } + [BackgroundDependencyLoader] private void load(OsuColour colours, OsuGame? game) { @@ -153,6 +183,10 @@ namespace osu.Game.Graphics.UserInterfaceV2 Origin = Anchor.BottomLeft, RelativeSizeAxes = Axes.X, Width = 0.5f, + // the textbox is hidden when the control is unfocused, + // but clicking on the label should reach the textbox, + // therefore make it always present. + AlwaysPresent = true, CommitOnFocusLost = true, SelectAllOnFocus = true, OnInputError = () => @@ -162,6 +196,14 @@ namespace osu.Game.Graphics.UserInterfaceV2 }, TabbableContentContainer = tabbableContentContainer, }, + valueLabel = new TruncatingSpriteText + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + RelativeSizeAxes = Axes.X, + Width = 0.5f, + Padding = new MarginPadding { Right = 5 }, + }, slider = new InnerSlider { Anchor = Anchor.CentreRight, @@ -170,6 +212,9 @@ namespace osu.Game.Graphics.UserInterfaceV2 Width = 0.5f, Current = currentNumberInstantaneous, OnCommit = () => current.Value = currentNumberInstantaneous.Value, + TooltipFormat = TooltipFormat, + DisplayAsPercentage = DisplayAsPercentage, + PlaySamplesOnAdjust = PlaySamplesOnAdjust, } }, }, @@ -218,6 +263,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 current.CopyTo(currentNumberInstantaneous); currentLanguage.BindValueChanged(_ => Schedule(updateValueDisplay)); + currentNumberInstantaneous.BindDisabledChanged(_ => updateState()); currentNumberInstantaneous.BindValueChanged(e => { if (!TransferValueOnCommit) @@ -299,15 +345,20 @@ namespace osu.Game.Graphics.UserInterfaceV2 { bool childHasFocus = slider.Focused.Value || textBox.Focused.Value; - textBox.Alpha = 1; - textBox.ReadOnly = Current.Disabled; + textBox.ReadOnly = currentNumberInstantaneous.Disabled; + textBox.Alpha = textBox.Focused.Value ? 1 : 0; + valueLabel.Alpha = textBox.Focused.Value ? 0 : 1; - background.Colour = currentNumberInstantaneous.Disabled ? colourProvider.Background4 : colourProvider.Background5; - captionText.Colour = currentNumberInstantaneous.Disabled ? colourProvider.Foreground1 : colourProvider.Content2; - textBox.Colour = currentNumberInstantaneous.Disabled ? colourProvider.Foreground1 : colourProvider.Content1; + captionText.Colour = currentNumberInstantaneous.Disabled ? colourProvider.Background1 : colourProvider.Content2; + textBox.Colour = currentNumberInstantaneous.Disabled ? colourProvider.Background1 : colourProvider.Content1; + valueLabel.Colour = currentNumberInstantaneous.Disabled ? colourProvider.Background1 : colourProvider.Content1; BorderThickness = childHasFocus || IsHovered || slider.IsDragging.Value ? 2 : 0; - BorderColour = childHasFocus ? colourProvider.Highlight1 : colourProvider.Light4; + + if (Current.Disabled) + BorderColour = colourProvider.Dark1; + else + BorderColour = childHasFocus ? colourProvider.Highlight1 : colourProvider.Light4; if (childHasFocus) background.Colour = ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark3); @@ -321,19 +372,28 @@ namespace osu.Game.Graphics.UserInterfaceV2 { if (updatingFromTextBox) return; - textBox.Text = slider.GetDisplayableValue(currentNumberInstantaneous.Value).ToString(); + textBox.Text = currentNumberInstantaneous.Value.ToStandardFormattedString(OsuSliderBar.MAX_DECIMAL_DIGITS); + valueLabel.Text = LabelFormat(currentNumberInstantaneous.Value); } + private LocalisableString defaultLabelFormat(T value) => currentNumberInstantaneous.Value.ToStandardFormattedString(OsuSliderBar.MAX_DECIMAL_DIGITS, DisplayAsPercentage); + private partial class InnerSlider : OsuSliderBar { public BindableBool Focused { get; } = new BindableBool(); public BindableBool IsDragging { get; set; } = new BindableBool(); + public Action? OnCommit { get; set; } + public sealed override LocalisableString TooltipText => base.TooltipText; + + public required Func TooltipFormat { get; init; } + private Box leftBox = null!; private Box rightBox = null!; private InnerSliderNub nub = null!; + private HoverClickSounds sounds = null!; public const float NUB_WIDTH = 10; [Resolved] @@ -382,7 +442,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 } } }, - new HoverClickSounds() + sounds = new HoverClickSounds() }; } @@ -442,6 +502,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 private void updateState() { + sounds.Enabled.Value = !Current.Disabled; rightBox.Colour = colourProvider.Background6; if (Current.Disabled) @@ -470,6 +531,8 @@ namespace osu.Game.Graphics.UserInterfaceV2 return result; } + + protected sealed override LocalisableString GetTooltipText(T value) => TooltipFormat(value); } private partial class InnerSliderNub : Circle diff --git a/osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs b/osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs index 4981557e37..6429eb6e96 100644 --- a/osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs +++ b/osu.Game/Graphics/UserInterfaceV2/FormTextBox.cs @@ -189,26 +189,22 @@ namespace osu.Game.Graphics.UserInterfaceV2 textBox.ReadOnly = disabled; textBox.Alpha = 1; - caption.Colour = disabled ? colourProvider.Foreground1 : colourProvider.Content2; + caption.Colour = disabled ? colourProvider.Background1 : colourProvider.Content2; textBox.Colour = disabled ? colourProvider.Foreground1 : colourProvider.Content1; - if (!disabled) - { - BorderThickness = IsHovered || textBox.Focused.Value ? 2 : 0; + BorderThickness = IsHovered || textBox.Focused.Value ? 2 : 0; + + if (disabled) + BorderColour = colourProvider.Dark1; + else BorderColour = textBox.Focused.Value ? colourProvider.Highlight1 : colourProvider.Light4; - if (textBox.Focused.Value) - background.Colour = ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark3); - else if (IsHovered) - background.Colour = ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark4); - else - background.Colour = colourProvider.Background5; - } + if (textBox.Focused.Value) + background.Colour = ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark3); + else if (IsHovered) + background.Colour = ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Dark4); else - { - BorderThickness = 0; - background.Colour = colourProvider.Background4; - } + background.Colour = colourProvider.Background5; } internal partial class InnerTextBox : OsuTextBox diff --git a/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs b/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs index cf569a73ca..1c1dae0f31 100644 --- a/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs +++ b/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs @@ -4,7 +4,6 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; -using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; @@ -24,12 +23,12 @@ namespace osu.Game.Graphics.UserInterfaceV2 private const float padding = 1.25f; private readonly Box fill; - private readonly Container switchContainer; - private readonly Drawable switchCircle; - private readonly CircularBorderContainer circularContainer; + private readonly Container nubContainer; + private readonly Drawable nub; + private readonly CircularContainer content; - private Color4 enabledColour; - private Color4 disabledColour; + [Resolved] + private OverlayColourProvider colourProvider { get; set; } = null!; private Sample? sampleChecked; private Sample? sampleUnchecked; @@ -38,7 +37,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 { Size = new Vector2(45, 20); - InternalChild = circularContainer = new CircularBorderContainer + InternalChild = content = new CircularContainer { RelativeSizeAxes = Axes.Both, BorderColour = Color4.White, @@ -56,15 +55,14 @@ namespace osu.Game.Graphics.UserInterfaceV2 { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding(border_thickness + padding), - Child = switchContainer = new Container + Child = nubContainer = new Container { RelativeSizeAxes = Axes.Both, - Child = switchCircle = new CircularContainer + Child = nub = new Circle { RelativeSizeAxes = Axes.Both, FillMode = FillMode.Fit, Masking = true, - Child = new Box { RelativeSizeAxes = Axes.Both } } } } @@ -73,14 +71,8 @@ namespace osu.Game.Graphics.UserInterfaceV2 } [BackgroundDependencyLoader(true)] - private void load(OverlayColourProvider? colourProvider, OsuColour colours, AudioManager audio) + private void load(AudioManager audio) { - enabledColour = colourProvider?.Highlight1 ?? colours.BlueDark; - disabledColour = colourProvider?.Background3 ?? colours.Gray3; - - switchContainer.Colour = enabledColour; - fill.Colour = disabledColour; - sampleChecked = audio.Samples.Get(@"UI/check-on"); sampleUnchecked = audio.Samples.Get(@"UI/check-off"); } @@ -89,27 +81,29 @@ namespace osu.Game.Graphics.UserInterfaceV2 { base.LoadComplete(); - Current.BindValueChanged(updateState, true); + Current.BindDisabledChanged(_ => updateColours()); + Current.BindValueChanged(_ => updateState(), true); + FinishTransforms(true); } - private void updateState(ValueChangedEvent state) + private void updateState() { - switchCircle.MoveToX(state.NewValue ? switchContainer.DrawWidth - switchCircle.DrawWidth : 0, 200, Easing.OutQuint); - fill.FadeTo(state.NewValue ? 1 : 0, 250, Easing.OutQuint); + nub.MoveToX(Current.Value ? nubContainer.DrawWidth - nub.DrawWidth : 0, 200, Easing.OutQuint); + fill.FadeTo(Current.Value ? 1 : 0, 250, Easing.OutQuint); - updateBorder(); + updateColours(); } protected override bool OnHover(HoverEvent e) { - updateBorder(); + updateColours(); return base.OnHover(e); } protected override void OnHoverLost(HoverLostEvent e) { - updateBorder(); + updateColours(); base.OnHoverLost(e); } @@ -123,15 +117,35 @@ namespace osu.Game.Graphics.UserInterfaceV2 sampleUnchecked?.Play(); } - private void updateBorder() + private void updateColours() { - circularContainer.TransformBorderTo((Current.Value ? enabledColour : disabledColour).Lighten(IsHovered ? 0.3f : 0)); - } + ColourInfo borderColour; + ColourInfo switchColour; - private partial class CircularBorderContainer : CircularContainer - { - public void TransformBorderTo(ColourInfo colour) - => this.TransformTo(nameof(BorderColour), colour, 250, Easing.OutQuint); + if (Current.Disabled) + { + borderColour = colourProvider.Dark2; + switchColour = colourProvider.Dark1; + fill.Colour = colourProvider.Dark5; + } + else + { + bool hover = IsHovered && !Current.Disabled; + + borderColour = hover ? colourProvider.Highlight1.Opacity(0.5f) : colourProvider.Highlight1.Opacity(0.3f); + switchColour = hover ? colourProvider.Highlight1 : colourProvider.Light4; + + if (!Current.Value) + { + borderColour = borderColour.MultiplyAlpha(0.8f); + switchColour = switchColour.MultiplyAlpha(0.8f); + } + + fill.Colour = colourProvider.Background6; + } + + nubContainer.FadeColour(switchColour, 250, Easing.OutQuint); + content.TransformTo(nameof(BorderColour), borderColour, 250, Easing.OutQuint); } } }