Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
8a581f5
Fix sliders not playing samples on adjust
frenzibyte Dec 31, 2025
27abce7
Allow dynamically configuring dropdown hint text
frenzibyte Dec 31, 2025
7ea1bbf
Introduce and use constants and classes for new settings overlay
frenzibyte Dec 31, 2025
e548cd4
Update game settings to use new form controls
frenzibyte Dec 31, 2025
874e3ad
Update layout settings section to use new controls
frenzibyte Dec 31, 2025
5d9ea9d
Rewrite input settings and use new form controls
frenzibyte Dec 31, 2025
ed760e6
Update keybind settings to use new revert button
frenzibyte Dec 31, 2025
30a60d8
Allow configuring settings note text anchor
frenzibyte Dec 31, 2025
96c414b
Adjust audio offset controls to match design language
frenzibyte Dec 31, 2025
c5a30d3
Remove unnecessary classic default specification
frenzibyte Dec 31, 2025
b9a3745
Shorten "increase first object visibility" label text
frenzibyte Dec 31, 2025
876dcd0
Reduce supporter note to informational
frenzibyte Jan 1, 2026
029d544
Adjust switch buttons to make the state more obvious
peppy Jan 9, 2026
ed091dc
Adjust toggleable subsection colour to always be bright when enabled
peppy Jan 9, 2026
3f92b45
Use `foreach` isntead of `ForEach`
peppy Jan 14, 2026
367d133
Avoid requiring private variables to set `ApplyClassicDefault` settings
peppy Jan 15, 2026
a675615
Update tablet area selection to match new design
peppy Jan 15, 2026
cd433fe
Fix weirdly defined constant
peppy Jan 15, 2026
42302c4
Merge branch 'master' into new-settings/overlay
peppy Jan 22, 2026
d4cf46e
Fix some intermittent test failures
peppy Jan 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 20 additions & 22 deletions osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Localisation;
using osu.Game.Graphics.UserInterface;
using osu.Game.Graphics.UserInterfaceV2;
using osu.Game.Localisation;
using osu.Game.Overlays.Settings;
using osu.Game.Rulesets.Mania.Configuration;
Expand All @@ -31,47 +31,45 @@ private void load()

Children = new Drawable[]
{
new SettingsEnumDropdown<ManiaScrollingDirection>
new SettingsItemV2(new FormEnumDropdown<ManiaScrollingDirection>
{
LabelText = RulesetSettingsStrings.ScrollingDirection,
Caption = RulesetSettingsStrings.ScrollingDirection,
Current = config.GetBindable<ManiaScrollingDirection>(ManiaRulesetSetting.ScrollDirection)
},
new SettingsSlider<double, ManiaScrollSlider>
}),
new SettingsItemV2(new FormSliderBar<double>
{
LabelText = RulesetSettingsStrings.ScrollSpeed,
Caption = RulesetSettingsStrings.ScrollSpeed,
Current = config.GetBindable<double>(ManiaRulesetSetting.ScrollSpeed),
KeyboardStep = 1
},
new SettingsCheckbox
KeyboardStep = 1,
LabelFormat = v => RulesetSettingsStrings.ScrollSpeedTooltip((int)DrawableManiaRuleset.ComputeScrollTime(v), v),
}),
new SettingsItemV2(new FormCheckBox
{
Keywords = new[] { "color" },
LabelText = RulesetSettingsStrings.TimingBasedColouring,
Caption = RulesetSettingsStrings.TimingBasedColouring,
Current = config.GetBindable<bool>(ManiaRulesetSetting.TimingBasedNoteColouring),
})
{
Keywords = new[] { "color" },
},
};

Add(new SettingsCheckbox
Add(new SettingsItemV2(new FormCheckBox
{
LabelText = RulesetSettingsStrings.TouchOverlay,
Caption = RulesetSettingsStrings.TouchOverlay,
Current = config.GetBindable<bool>(ManiaRulesetSetting.TouchOverlay)
});
}));

if (RuntimeInfo.IsMobile)
{
Add(new SettingsEnumDropdown<ManiaMobileLayout>
Add(new SettingsItemV2(new FormEnumDropdown<ManiaMobileLayout>
{
LabelText = RulesetSettingsStrings.MobileLayout,
Caption = RulesetSettingsStrings.MobileLayout,
Current = config.GetBindable<ManiaMobileLayout>(ManiaRulesetSetting.MobileLayout),
#pragma warning disable CS0618 // Type or member is obsolete
Items = Enum.GetValues<ManiaMobileLayout>().Where(l => l != ManiaMobileLayout.LandscapeWithOverlay),
#pragma warning restore CS0618 // Type or member is obsolete
});
}));
}
}

private partial class ManiaScrollSlider : RoundedSliderBar<double>
{
public override LocalisableString TooltipText => RulesetSettingsStrings.ScrollSpeedTooltip((int)DrawableManiaRuleset.ComputeScrollTime(Current.Value), Current.Value);
}
}
}
34 changes: 19 additions & 15 deletions osu.Game.Rulesets.Osu/UI/OsuSettingsSubsection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@

using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Localisation;
using osu.Game.Graphics.UserInterfaceV2;
using osu.Game.Localisation;
using osu.Game.Overlays.Settings;
using osu.Game.Rulesets.Osu.Configuration;
Expand All @@ -27,32 +29,34 @@ private void load()

Children = new Drawable[]
{
new SettingsCheckbox
new SettingsItemV2(new FormCheckBox
{
LabelText = RulesetSettingsStrings.SnakingInSliders,
Caption = RulesetSettingsStrings.SnakingInSliders,
Current = config.GetBindable<bool>(OsuRulesetSetting.SnakingInSliders)
},
new SettingsCheckbox
}),
new SettingsItemV2(new FormCheckBox
{
ClassicDefault = false,
LabelText = RulesetSettingsStrings.SnakingOutSliders,
Caption = RulesetSettingsStrings.SnakingOutSliders,
Current = config.GetBindable<bool>(OsuRulesetSetting.SnakingOutSliders)
})
{
ApplyClassicDefault = c => ((IHasCurrentValue<bool>)c).Current.Value = false,
},
new SettingsCheckbox
new SettingsItemV2(new FormCheckBox
{
LabelText = RulesetSettingsStrings.CursorTrail,
Caption = RulesetSettingsStrings.CursorTrail,
Current = config.GetBindable<bool>(OsuRulesetSetting.ShowCursorTrail)
},
new SettingsCheckbox
}),
new SettingsItemV2(new FormCheckBox
{
LabelText = RulesetSettingsStrings.CursorRipples,
Caption = RulesetSettingsStrings.CursorRipples,
Current = config.GetBindable<bool>(OsuRulesetSetting.ShowCursorRipples)
},
new SettingsEnumDropdown<PlayfieldBorderStyle>
}),
new SettingsItemV2(new FormEnumDropdown<PlayfieldBorderStyle>
{
LabelText = RulesetSettingsStrings.PlayfieldBorderStyle,
Caption = RulesetSettingsStrings.PlayfieldBorderStyle,
Current = config.GetBindable<PlayfieldBorderStyle>(OsuRulesetSetting.PlayfieldBorderStyle),
},
}),
};
}
}
Expand Down
7 changes: 4 additions & 3 deletions osu.Game.Rulesets.Taiko/TaikoSettingsSubsection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Localisation;
using osu.Game.Graphics.UserInterfaceV2;
using osu.Game.Localisation;
using osu.Game.Overlays.Settings;
using osu.Game.Rulesets.Taiko.Configuration;
Expand All @@ -26,11 +27,11 @@ private void load()

Children = new Drawable[]
{
new SettingsEnumDropdown<TaikoTouchControlScheme>
new SettingsItemV2(new FormEnumDropdown<TaikoTouchControlScheme>
{
LabelText = RulesetSettingsStrings.TouchControlScheme,
Caption = RulesetSettingsStrings.TouchControlScheme,
Current = config.GetBindable<TaikoTouchControlScheme>(TaikoRulesetSetting.TouchControlScheme)
}
})
};
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using osu.Framework.Testing;
using osu.Framework.Utils;
using osu.Game.Configuration;
using osu.Game.Overlays;
using osu.Game.Overlays.Settings.Sections.Audio;
using osu.Game.Scoring;
using osu.Game.Tests.Visual.Ranking;
Expand All @@ -25,6 +26,9 @@ public partial class TestSceneAudioOffsetAdjustControl : OsuTestScene
[Cached]
private SessionAverageHitErrorTracker tracker = new SessionAverageHitErrorTracker();

[Cached]
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple);

private Container content = null!;
protected override Container Content => content;

Expand Down
15 changes: 8 additions & 7 deletions osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using osu.Game.Graphics.UserInterfaceV2;
using osu.Game.Localisation;
using osu.Game.Overlays;
using osu.Game.Overlays.Settings;
using osu.Game.Overlays.Settings.Sections.Input;
using osu.Game.Rulesets.Taiko;
using osuTK.Input;
Expand Down Expand Up @@ -202,16 +203,16 @@ public void TestSingleBindingResetButton()
InputManager.ReleaseKey(Key.P);
});

AddUntilStep("restore button shown", () => settingsKeyBindingRow.ChildrenOfType<RevertToDefaultButton<bool>>().First().Alpha > 0);
AddUntilStep("restore button shown", () => settingsKeyBindingRow.ChildrenOfType<SettingsRevertToDefaultButton>().First().Alpha > 0);

AddStep("click reset button for bindings", () =>
{
var resetButton = settingsKeyBindingRow.ChildrenOfType<RevertToDefaultButton<bool>>().First();
var resetButton = settingsKeyBindingRow.ChildrenOfType<SettingsRevertToDefaultButton>().First();

resetButton.TriggerClick();
});

AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType<RevertToDefaultButton<bool>>().First().Alpha == 0);
AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType<SettingsRevertToDefaultButton>().First().Alpha == 0);

AddAssert("binding cleared",
() => settingsKeyBindingRow.ChildrenOfType<KeyBindingRow.KeyButton>().ElementAt(0).KeyBinding.Value.KeyCombination.Equals(settingsKeyBindingRow.Defaults.ElementAt(0)));
Expand All @@ -232,7 +233,7 @@ public void TestResetAllBindingsButton()
InputManager.ReleaseKey(Key.P);
});

AddUntilStep("restore button shown", () => settingsKeyBindingRow.ChildrenOfType<RevertToDefaultButton<bool>>().First().Alpha > 0);
AddUntilStep("restore button shown", () => settingsKeyBindingRow.ChildrenOfType<SettingsRevertToDefaultButton>().First().Alpha > 0);

AddStep("click reset button for bindings", () =>
{
Expand All @@ -241,7 +242,7 @@ public void TestResetAllBindingsButton()
resetButton.TriggerClick();
});

AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType<RevertToDefaultButton<bool>>().First().Alpha == 0);
AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType<SettingsRevertToDefaultButton>().First().Alpha == 0);

AddAssert("binding cleared",
() => settingsKeyBindingRow.ChildrenOfType<KeyBindingRow.KeyButton>().ElementAt(0).KeyBinding.Value.KeyCombination.Equals(settingsKeyBindingRow.Defaults.ElementAt(0)));
Expand Down Expand Up @@ -394,7 +395,7 @@ public void TestBindingConflictCausedByResetToDefaultOfSingleRow()
AddStep("reset Left (centre) to default", () =>
{
var row = panel.ChildrenOfType<KeyBindingRow>().First(r => r.ChildrenOfType<OsuSpriteText>().Any(s => s.Text.ToString() == "Left (centre)"));
row.ChildrenOfType<RevertToDefaultButton<bool>>().Single().TriggerClick();
row.ChildrenOfType<SettingsRevertToDefaultButton>().Single().TriggerClick();
});

KeyBindingConflictPopover popover = null;
Expand Down Expand Up @@ -450,7 +451,7 @@ public void TestResettingRowCannotConflictWithItself()
AddStep("revert row to default", () =>
{
var row = panel.ChildrenOfType<KeyBindingRow>().First(r => r.ChildrenOfType<OsuSpriteText>().Any(s => s.Text.ToString() == "Left (centre)"));
InputManager.MoveMouseTo(row.ChildrenOfType<RevertToDefaultButton<bool>>().Single());
InputManager.MoveMouseTo(row.ChildrenOfType<SettingsRevertToDefaultButton>().Single());
InputManager.Click(MouseButton.Left);
});
AddWaitStep("wait a bit", 3);
Expand Down
5 changes: 3 additions & 2 deletions osu.Game.Tests/Visual/Settings/TestSceneKeyBindingRow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using osu.Framework.Testing;
using osu.Game.Input.Bindings;
using osu.Game.Overlays;
using osu.Game.Overlays.Settings;
using osu.Game.Overlays.Settings.Sections.Input;

namespace osu.Game.Tests.Visual.Settings
Expand Down Expand Up @@ -45,7 +46,7 @@ public void TestChangesAfterConstruction()
row.KeyBindings.Add(new RealmKeyBinding(GlobalAction.Back, new KeyCombination(InputKey.Escape)));
row.KeyBindings.Add(new RealmKeyBinding(GlobalAction.Back, new KeyCombination(InputKey.ExtraMouseButton1)));
});
AddUntilStep("revert to default button not shown", () => row.ChildrenOfType<RevertToDefaultButton<bool>>().Single().Alpha, () => Is.Zero);
AddUntilStep("revert to default button not shown", () => row.ChildrenOfType<SettingsRevertToDefaultButton>().Single().Alpha, () => Is.Zero);

AddStep("change key bindings", () =>
{
Expand All @@ -54,7 +55,7 @@ public void TestChangesAfterConstruction()
row.KeyBindings.Add(new RealmKeyBinding(GlobalAction.Back, new KeyCombination(InputKey.Z)));
row.KeyBindings.Add(new RealmKeyBinding(GlobalAction.Back, new KeyCombination(InputKey.I)));
});
AddUntilStep("revert to default button not shown", () => row.ChildrenOfType<RevertToDefaultButton<bool>>().Single().Alpha, () => Is.Not.Zero);
AddUntilStep("revert to default button not shown", () => row.ChildrenOfType<SettingsRevertToDefaultButton>().Single().Alpha, () => Is.Not.Zero);
}
}
}
6 changes: 3 additions & 3 deletions osu.Game.Tests/Visual/Settings/TestSceneSettingsItemV2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Graphics.Containers;
Expand All @@ -31,7 +32,6 @@ public partial class TestSceneSettingsItemV2 : ThemeComparisonTestScene
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple);

private FormSliderBar<float> sliderBar = null!;
private FormSliderBar<float> classicSliderBar = null!;

private SearchContainer searchContainer = null!;

Expand Down Expand Up @@ -173,7 +173,7 @@ protected override Drawable CreateContent()
{
ShowRevertToDefaultButton = false
},
new SettingsItemV2(classicSliderBar = new FormSliderBar<float>
new SettingsItemV2(new FormSliderBar<float>
{
Caption = "Slider with classic default",
Current = new BindableFloat
Expand All @@ -185,7 +185,7 @@ protected override Drawable CreateContent()
},
})
{
ApplyClassicDefault = () => classicSliderBar.Current.Value = 2,
ApplyClassicDefault = c => ((IHasCurrentValue<float>)c).Current.Value = 2,
},
},
},
Expand Down
7 changes: 4 additions & 3 deletions osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Input.Handlers;
using osu.Framework.Input.Handlers.Tablet;
using osu.Framework.Testing;
using osu.Framework.Utils;
Expand Down Expand Up @@ -69,7 +70,7 @@ public void TestWideAspectRatioValidity()
{
AddStep("Test with wide tablet", () => tabletHandler.SetTabletSize(new Vector2(160, 100)));

AddStep("Reset to full area", () => settings.ChildrenOfType<DangerousSettingsButton>().First().TriggerClick());
AddStep("Reset to full area", () => settings.ChildrenOfType<DangerousSettingsButtonV2>().First().TriggerClick());
ensureValid();

AddStep("rotate 10", () => tabletHandler.Rotation.Value = 10);
Expand Down Expand Up @@ -129,7 +130,7 @@ public void TestOffsetValidity()

private void ensureInvalid() => AddAssert("area invalid", () => !settings.AreaSelection.IsWithinBounds);

public class TestTabletHandler : ITabletHandler
public class TestTabletHandler : InputHandler, ITabletHandler
{
public Bindable<Vector2> AreaOffset { get; } = new Bindable<Vector2>();
public Bindable<Vector2> AreaSize { get; } = new Bindable<Vector2>();
Expand All @@ -149,7 +150,7 @@ public class TestTabletHandler : ITabletHandler

private readonly Bindable<TabletInfo> tablet = new Bindable<TabletInfo>();

public BindableBool Enabled { get; } = new BindableBool(true);
public override bool IsActive => true;

public void SetTabletSize(Vector2 size)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@
SortBy(SortMode.Artist);
checkMatchedBeatmaps(6);

AddUntilStep("wait for spread indicator", () => this.ChildrenOfType<PanelBeatmapStandalone.SpreadDisplay>().Any(d => d.Enabled.Value));

Check failure on line 392 in osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs

View workflow job for this annotation

GitHub Actions / Results

osu.Game.Tests.Visual.SongSelectV2.TestSceneSongSelectFiltering ► TestScopeToBeatmapWhenDifficultiesGroupedBySet

Failed test found in: TestResults-Linux-SingleThread.trx Error: "wait for spread indicator" timed out
Raw output
"wait for spread indicator" timed out
   at osu.Game.Tests.Visual.SongSelectV2.TestSceneSongSelectFiltering.TestScopeToBeatmapWhenDifficultiesGroupedBySet() in /home/runner/work/osu/osu/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs:line 392

AddStep("click spread indicator", () => this.ChildrenOfType<PanelBeatmapSet.SpreadDisplay>().Single(d => d.Enabled.Value).TriggerClick());
WaitForFiltering();
checkMatchedBeatmaps(3);
Expand All @@ -412,6 +413,7 @@
WaitForFiltering();
checkMatchedBeatmaps(3);

AddUntilStep("wait for spread indicator", () => this.ChildrenOfType<PanelBeatmapStandalone.SpreadDisplay>().Any(d => d.Enabled.Value));

Check failure on line 416 in osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs

View workflow job for this annotation

GitHub Actions / Results

osu.Game.Tests.Visual.SongSelectV2.TestSceneSongSelectFiltering ► TestDismissingScopeDoesNotClearSearchTextBox

Failed test found in: TestResults-Linux-SingleThread.trx Error: "wait for spread indicator" timed out
Raw output
"wait for spread indicator" timed out
   at osu.Game.Tests.Visual.SongSelectV2.TestSceneSongSelectFiltering.TestDismissingScopeDoesNotClearSearchTextBox() in /home/runner/work/osu/osu/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelectFiltering.cs:line 416

AddStep("click spread indicator", () => this.ChildrenOfType<PanelBeatmapSet.SpreadDisplay>().Single(d => d.Enabled.Value).TriggerClick());
WaitForFiltering();
checkMatchedBeatmaps(3);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public void TestSettingsButtonInput()
{
AddStep("Move cursor to button", () => InputManager.MoveMouseTo(settingsButton));
AddAssert("Button is hovered", () => settingsButton.IsHovered);
AddStep("Move cursor to padded area", () => InputManager.MoveMouseTo(settingsButton.ScreenSpaceDrawQuad.TopLeft + new Vector2(SettingsPanel.CONTENT_MARGINS / 2f, 10)));
AddStep("Move cursor to padded area", () => InputManager.MoveMouseTo(settingsButton.ScreenSpaceDrawQuad.TopLeft + new Vector2(SettingsPanel.CONTENT_PADDING.Left / 2f, 10)));
AddAssert("Cursor within a button", () => settingsButton.ScreenSpaceDrawQuad.Contains(InputManager.CurrentState.Mouse.Position));
AddAssert("Button is not hovered", () => !settingsButton.IsHovered);
}
Expand Down
6 changes: 5 additions & 1 deletion osu.Game/Graphics/UserInterfaceV2/FormDropdown.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ public partial class FormDropdown<T> : OsuDropdown<T>, IFormControl
/// <summary>
/// Hint text containing an extended description of this slider bar, displayed in a tooltip when hovering the caption.
/// </summary>
public LocalisableString HintText { get; init; }
public LocalisableString HintText
{
get => header.HintText;
set => header.HintText = value;
}

/// <summary>
/// The maximum height of the dropdown's menu.
Expand Down
4 changes: 2 additions & 2 deletions osu.Game/Graphics/UserInterfaceV2/FormSliderBar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ public float KeyboardStep
/// <summary>
/// Whether sound effects should play when adjusting this slider.
/// </summary>
public bool PlaySamplesOnAdjust { get; init; }
public bool PlaySamplesOnAdjust { get; init; } = true;

/// <summary>
/// The string formatting function to use for the value label.
Expand Down Expand Up @@ -418,7 +418,7 @@ private void updateValueDisplay()

private LocalisableString defaultLabelFormat(T value) => currentNumberInstantaneous.Value.ToStandardFormattedString(OsuSliderBar<T>.MAX_DECIMAL_DIGITS, DisplayAsPercentage);

private partial class InnerSlider : OsuSliderBar<T>
public partial class InnerSlider : OsuSliderBar<T>
{
public BindableBool Focused { get; } = new BindableBool();

Expand Down
Loading
Loading