1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-20 02:39:53 +08:00

Merge pull request #36116 from frenzibyte/new-settings/form-visuals

Prepare form controls for use in settings
This commit is contained in:
Dean Herbert
2025-12-25 03:16:12 +09:00
committed by GitHub
Unverified
11 changed files with 373 additions and 181 deletions
@@ -1,15 +1,18 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. 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<float>
{
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<CountdownType>
{
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<float>
{
Caption = "Slider",
HintText = "Slider hint",
Current = new BindableFloat
{
MinValue = 0,
MaxValue = 10,
Value = 5,
Precision = 0.1f,
},
TabbableContentContainer = this,
},
new FormSliderBar<float>
{
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<float>
{
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<float>
{
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<float>
{
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<CountdownType>
{
Caption = EditorSetupStrings.EnableCountdown,
HintText = EditorSetupStrings.CountdownDescription,
},
new FormEnumDropdown<CountdownType>
{
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;
}
}
}
}
@@ -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);
@@ -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;
});
}
}
}
@@ -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
{
@@ -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;
@@ -25,12 +25,12 @@ namespace osu.Game.Graphics.UserInterface
/// </summary>
public bool DisplayAsPercentage { get; set; }
public virtual LocalisableString TooltipText { get; private set; }
public virtual LocalisableString TooltipText { get; protected set; }
/// <summary>
/// Maximum number of decimal digits to be displayed in the tooltip.
/// </summary>
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);
}
}
@@ -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<LocalisableString> FilterTerms => Caption.Yield();
@@ -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()
@@ -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
}
}
/// <summary>
/// Whether to format the tooltip as a percentage or the actual value.
/// </summary>
public bool DisplayAsPercentage { get; init; }
/// <summary>
/// Whether sound effects should play when adjusting this slider.
/// </summary>
public bool PlaySamplesOnAdjust { get; init; }
/// <summary>
/// The string formatting function to use for the value label.
/// </summary>
public Func<T, LocalisableString> LabelFormat { get; init; }
/// <summary>
/// The string formatting function to use for the slider's tooltip text.
/// If not provided, <see cref="LabelFormat"/> is used.
/// </summary>
public Func<T, LocalisableString> 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<Language> currentLanguage = new Bindable<Language>();
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<T>.MAX_DECIMAL_DIGITS);
valueLabel.Text = LabelFormat(currentNumberInstantaneous.Value);
}
private LocalisableString defaultLabelFormat(T value) => currentNumberInstantaneous.Value.ToStandardFormattedString(OsuSliderBar<T>.MAX_DECIMAL_DIGITS, DisplayAsPercentage);
private partial class InnerSlider : OsuSliderBar<T>
{
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<T, LocalisableString> 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
@@ -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
@@ -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<bool> 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);
}
}
}