From b76a7e1bb64f0747ef06d832eb2e87d052ca030d Mon Sep 17 00:00:00 2001 From: Krzysztof Gutkowski Date: Thu, 5 Mar 2026 18:09:05 +0100 Subject: [PATCH] Refactor `ShearedButton` to allow easier relative sizing (#36802) This commit rearranges the contents of `ShearedButtons` to be more independent of each other in regards to sizing. Thanks to that, the custom logic related to enabling autosizing is no longer necessary. Witdh and height are no longer set via the constructor, and can be freely configured using the initializer syntax. Additionally, this allows the button to use relative sizing without having to resort to any hackery with `Size` (this will come in handy for me when implementing the new footer on multiplayer screens). Given that most of the `ShearedButton`s currently in use set their width explicitly, I did not set `AutoSizeAxes = Axes.X` like it would be by default previously. Instead it is set on the only two such buttons (show converts/selected mods on ssv2). I suppose it might be a good idea to have it set that by default if no `Width` is specified, as right now it'll just not show anything. Also I've set the margin on the text field by default in all cases instead of only when autosizing like how it was previously, since otherwise it would be a pain to set that on each button instance when needed. I've checked all affected components and could not find any text overflowing issues that this could cause. --------- Co-authored-by: Dean Herbert --- .../TestSceneScreenFooterNavigation.cs | 4 +- .../UserInterface/TestSceneButtonsInput.cs | 3 +- .../UserInterface/TestSceneScreenFooter.cs | 4 +- .../UserInterface/TestSceneShearedButtons.cs | 21 +++++-- .../Graphics/UserInterface/ShearedButton.cs | 62 +++++++------------ .../UserInterface/ShearedToggleButton.cs | 15 ----- osu.Game/Overlays/Mods/AddPresetButton.cs | 1 - osu.Game/Overlays/Mods/AddPresetPopover.cs | 3 +- .../Overlays/Mods/DeselectAllModsButton.cs | 3 +- osu.Game/Overlays/Mods/EditPresetPopover.cs | 6 +- osu.Game/Overlays/Mods/SelectAllModsButton.cs | 3 +- osu.Game/Overlays/WizardOverlay.cs | 3 +- osu.Game/Screens/Footer/ScreenBackButton.cs | 7 +-- .../Matchmaking/Queue/ScreenQueue.cs | 16 ++--- .../Playlists/AddToPlaylistFooterButton.cs | 7 +-- .../Select/BeatmapDetailsArea.Header.cs | 1 + .../FilterControl.ScopedBeatmapSetDisplay.cs | 3 +- osu.Game/Screens/Select/FilterControl.cs | 1 + 18 files changed, 67 insertions(+), 96 deletions(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenFooterNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenFooterNavigation.cs index 27c7528efa..7c8ff56a57 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenFooterNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenFooterNavigation.cs @@ -349,8 +349,8 @@ namespace osu.Game.Tests.Visual.Navigation AutoSizeAxes = Axes.Both, Children = new[] { - new ShearedButton(200) { Text = "Action #1", Action = () => { } }, - new ShearedButton(140) { Text = "Action #2", Action = () => { } }, + new ShearedButton { Width = 200, Text = "Action #1", Action = () => { } }, + new ShearedButton { Width = 140, Text = "Action #2", Action = () => { } }, } }; } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneButtonsInput.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneButtonsInput.cs index f30b82d618..5c98f27d86 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneButtonsInput.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneButtonsInput.cs @@ -72,12 +72,13 @@ namespace osu.Game.Tests.Visual.UserInterface Enabled = { Value = true }, Text = "Rounded button" }, - shearedButton = new ShearedButton(width) + shearedButton = new ShearedButton { Text = "Sheared button", LighterColour = Colour4.FromHex("#FFFFFF"), DarkerColour = Colour4.FromHex("#FFCC22"), TextColour = Colour4.Black, + Width = width, Height = 40, Enabled = { Value = true }, Padding = new MarginPadding(0) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneScreenFooter.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneScreenFooter.cs index a958c5f43e..97b7292497 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneScreenFooter.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneScreenFooter.cs @@ -342,8 +342,8 @@ namespace osu.Game.Tests.Visual.UserInterface AutoSizeAxes = Axes.Both, Children = new[] { - new ShearedButton(200) { Text = "Action #1", Action = () => { } }, - new ShearedButton(140) { Text = "Action #2", Action = () => { } }, + new ShearedButton { Width = 200, Text = "Action #1", Action = () => { } }, + new ShearedButton { Width = 140, Text = "Action #2", Action = () => { } }, } }; } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneShearedButtons.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneShearedButtons.cs index bdec96f446..f226920cb6 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneShearedButtons.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneShearedButtons.cs @@ -36,8 +36,10 @@ namespace osu.Game.Tests.Visual.UserInterface if (bigButton) { - Child = button = new ShearedButton(400, 80) + Child = button = new ShearedButton { + Width = 400, + Height = 80, LighterColour = Colour4.FromHex("#FFFFFF"), DarkerColour = Colour4.FromHex("#FFCC22"), TextColour = Colour4.Black, @@ -50,8 +52,10 @@ namespace osu.Game.Tests.Visual.UserInterface } else { - Child = button = new ShearedButton(200, 80) + Child = button = new ShearedButton { + Width = 200, + Height = 80, LighterColour = Colour4.FromHex("#FF86DD"), DarkerColour = Colour4.FromHex("#DE31AE"), TextColour = Colour4.White, @@ -79,8 +83,9 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("create button", () => { - Child = button = new ShearedToggleButton(200) + Child = button = new ShearedToggleButton { + Width = 200, Anchor = Anchor.Centre, Origin = Anchor.Centre, Text = "Toggle me", @@ -96,8 +101,9 @@ namespace osu.Game.Tests.Visual.UserInterface { ShearedToggleButton toggleButton = null; - AddStep("create fixed width button", () => Child = toggleButton = new ShearedToggleButton(200) + AddStep("create fixed width button", () => Child = toggleButton = new ShearedToggleButton { + Width = 200, Anchor = Anchor.Centre, Origin = Anchor.Centre, Text = "Fixed width" @@ -109,6 +115,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("create auto-sizing button", () => Child = toggleButton = new ShearedToggleButton { + AutoSizeAxes = Axes.X, Anchor = Anchor.Centre, Origin = Anchor.Centre, Text = "This button autosizes to its text!" @@ -130,8 +137,9 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("create button", () => { - Child = button = new ShearedToggleButton(200) + Child = button = new ShearedToggleButton { + Width = 200, Anchor = Anchor.Centre, Origin = Anchor.Centre, Text = "Toggle me", @@ -186,6 +194,7 @@ namespace osu.Game.Tests.Visual.UserInterface { new ShearedButton { + AutoSizeAxes = Axes.X, Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, Text = "Button", @@ -194,6 +203,7 @@ namespace osu.Game.Tests.Visual.UserInterface }, new ShearedButton { + AutoSizeAxes = Axes.X, Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, Text = "Button", @@ -202,6 +212,7 @@ namespace osu.Game.Tests.Visual.UserInterface }, new ShearedButton { + AutoSizeAxes = Axes.X, Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, Text = "Button", diff --git a/osu.Game/Graphics/UserInterface/ShearedButton.cs b/osu.Game/Graphics/UserInterface/ShearedButton.cs index 2047fc74f4..e6737d6a57 100644 --- a/osu.Game/Graphics/UserInterface/ShearedButton.cs +++ b/osu.Game/Graphics/UserInterface/ShearedButton.cs @@ -75,19 +75,15 @@ namespace osu.Game.Graphics.UserInterface protected readonly Container ButtonContent; /// - /// Creates a new + /// Creates a new /// - /// - /// The width of the button. - /// - /// If a non- value is provided, this button will have a fixed width equal to the provided value. - /// If a value is provided (or the argument is omitted entirely), the button will autosize in width to fit the text. - /// - /// - /// The height of the button. - public ShearedButton(float? width = null, float height = DEFAULT_HEIGHT) + /// + /// By default, the button will have a height of . + /// Width should be set for each usage. + /// + public ShearedButton() { - Height = height; + Height = DEFAULT_HEIGHT; Shear = OsuGame.SHEAR; @@ -99,27 +95,25 @@ namespace osu.Game.Graphics.UserInterface { backgroundLayer = new Container { - RelativeSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.Both, CornerRadius = CORNER_RADIUS, Masking = true, BorderThickness = BORDER_THICKNESS, - Children = new Drawable[] + Child = background = new Box { - background = new Box - { - RelativeSizeAxes = Axes.Both - }, - ButtonContent = new Container - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AutoSizeAxes = Axes.Both, - Shear = -OsuGame.SHEAR, - Child = text = new OsuSpriteText - { - Font = OsuFont.TorusAlternate.With(size: 17), - } - }, + RelativeSizeAxes = Axes.Both, + }, + }, + ButtonContent = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Shear = -OsuGame.SHEAR, + Child = text = new OsuSpriteText + { + Font = OsuFont.TorusAlternate.With(size: 17), + Margin = new MarginPadding { Horizontal = 15 }, } }, flashLayer = new Box @@ -130,18 +124,6 @@ namespace osu.Game.Graphics.UserInterface Alpha = 0, }, }; - - if (width != null) - { - Width = width.Value; - backgroundLayer.RelativeSizeAxes = Axes.Both; - } - else - { - AutoSizeAxes = Axes.X; - backgroundLayer.AutoSizeAxes = Axes.X; - text.Margin = new MarginPadding { Horizontal = 15 }; - } } protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverClickSounds(sampleSet) { Enabled = { BindTarget = Enabled } }; diff --git a/osu.Game/Graphics/UserInterface/ShearedToggleButton.cs b/osu.Game/Graphics/UserInterface/ShearedToggleButton.cs index c2f547ba19..7731425635 100644 --- a/osu.Game/Graphics/UserInterface/ShearedToggleButton.cs +++ b/osu.Game/Graphics/UserInterface/ShearedToggleButton.cs @@ -24,21 +24,6 @@ namespace osu.Game.Graphics.UserInterface /// public BindableBool Active { get; } = new BindableBool(); - /// - /// Creates a new - /// - /// - /// The width of the button. - /// - /// If a non- value is provided, this button will have a fixed width equal to the provided value. - /// If a value is provided (or the argument is omitted entirely), the button will autosize in width to fit the text. - /// - /// - public ShearedToggleButton(float? width = null) - : base(width) - { - } - [BackgroundDependencyLoader] private void load(AudioManager audio) { diff --git a/osu.Game/Overlays/Mods/AddPresetButton.cs b/osu.Game/Overlays/Mods/AddPresetButton.cs index e4f7f83c11..0844291f91 100644 --- a/osu.Game/Overlays/Mods/AddPresetButton.cs +++ b/osu.Game/Overlays/Mods/AddPresetButton.cs @@ -27,7 +27,6 @@ namespace osu.Game.Overlays.Mods private Bindable> selectedMods { get; set; } = null!; public AddPresetButton() - : base(1) { RelativeSizeAxes = Axes.X; Height = ModSelectPanel.HEIGHT; diff --git a/osu.Game/Overlays/Mods/AddPresetPopover.cs b/osu.Game/Overlays/Mods/AddPresetPopover.cs index 817a61f7ac..831f03f78c 100644 --- a/osu.Game/Overlays/Mods/AddPresetPopover.cs +++ b/osu.Game/Overlays/Mods/AddPresetPopover.cs @@ -74,11 +74,12 @@ namespace osu.Game.Overlays.Mods Direction = FillDirection.Vertical, Children = new Drawable[] { - createButton = new ShearedButton(content_width) + createButton = new ShearedButton { // todo: for some very odd reason, this needs to be anchored to topright for the fill flow to be correctly sized to the AABB of the sheared button Anchor = Anchor.TopRight, Origin = Anchor.TopRight, + Width = content_width, Text = ModSelectOverlayStrings.AddPreset, Action = createPreset } diff --git a/osu.Game/Overlays/Mods/DeselectAllModsButton.cs b/osu.Game/Overlays/Mods/DeselectAllModsButton.cs index 0e60fc3414..9b8ae1e3b6 100644 --- a/osu.Game/Overlays/Mods/DeselectAllModsButton.cs +++ b/osu.Game/Overlays/Mods/DeselectAllModsButton.cs @@ -15,8 +15,9 @@ namespace osu.Game.Overlays.Mods private readonly Bindable> selectedMods = new Bindable>(); public DeselectAllModsButton(ModSelectOverlay modSelectOverlay) - : base(ModSelectOverlay.BUTTON_WIDTH) { + Width = ModSelectOverlay.BUTTON_WIDTH; + Text = CommonStrings.DeselectAll; Action = modSelectOverlay.DeselectAll; diff --git a/osu.Game/Overlays/Mods/EditPresetPopover.cs b/osu.Game/Overlays/Mods/EditPresetPopover.cs index eb128c7792..820ffad265 100644 --- a/osu.Game/Overlays/Mods/EditPresetPopover.cs +++ b/osu.Game/Overlays/Mods/EditPresetPopover.cs @@ -114,22 +114,24 @@ namespace osu.Game.Overlays.Mods Direction = FillDirection.Vertical, Children = new Drawable[] { - useCurrentModsButton = new ShearedButton(content_width) + useCurrentModsButton = new ShearedButton { // todo: for some very odd reason, this needs to be anchored to topright for the fill flow to be correctly sized to the AABB of the sheared button Anchor = Anchor.TopRight, Origin = Anchor.TopRight, + Width = content_width, Text = ModSelectOverlayStrings.UseCurrentMods, DarkerColour = colours.Blue1, LighterColour = colours.Blue0, TextColour = colourProvider.Background6, Action = useCurrentMods, }, - saveButton = new ShearedButton(content_width) + saveButton = new ShearedButton { // todo: for some very odd reason, this needs to be anchored to topright for the fill flow to be correctly sized to the AABB of the sheared button Anchor = Anchor.TopRight, Origin = Anchor.TopRight, + Width = content_width, Text = Resources.Localisation.Web.CommonStrings.ButtonsSave, DarkerColour = colours.Orange1, LighterColour = colours.Orange0, diff --git a/osu.Game/Overlays/Mods/SelectAllModsButton.cs b/osu.Game/Overlays/Mods/SelectAllModsButton.cs index 1da762d164..2fb72ef2c4 100644 --- a/osu.Game/Overlays/Mods/SelectAllModsButton.cs +++ b/osu.Game/Overlays/Mods/SelectAllModsButton.cs @@ -18,8 +18,9 @@ namespace osu.Game.Overlays.Mods private readonly Bindable searchTerm = new Bindable(); public SelectAllModsButton(FreeModSelectOverlay modSelectOverlay) - : base(ModSelectOverlay.BUTTON_WIDTH) { + Width = ModSelectOverlay.BUTTON_WIDTH; + Text = CommonStrings.SelectAll; Action = modSelectOverlay.SelectAll; diff --git a/osu.Game/Overlays/WizardOverlay.cs b/osu.Game/Overlays/WizardOverlay.cs index 3cc403dbff..a75f1aff3c 100644 --- a/osu.Game/Overlays/WizardOverlay.cs +++ b/osu.Game/Overlays/WizardOverlay.cs @@ -245,10 +245,9 @@ namespace osu.Game.Overlays Padding = new MarginPadding { Right = OsuGame.SCREEN_EDGE_MARGIN }; - InternalChild = NextButton = new ShearedButton(0) + InternalChild = NextButton = new ShearedButton { RelativeSizeAxes = Axes.X, - Width = 1, Text = FirstRunSetupOverlayStrings.GetStarted, DarkerColour = colourProvider.Colour3, LighterColour = colourProvider.Colour2, diff --git a/osu.Game/Screens/Footer/ScreenBackButton.cs b/osu.Game/Screens/Footer/ScreenBackButton.cs index 481192088c..37d4260d18 100644 --- a/osu.Game/Screens/Footer/ScreenBackButton.cs +++ b/osu.Game/Screens/Footer/ScreenBackButton.cs @@ -32,14 +32,11 @@ namespace osu.Game.Screens.Footer return inputRectangle.Contains(ToLocalSpace(screenSpacePos)); } - public ScreenBackButton() - : base(BUTTON_WIDTH) - { - } - [BackgroundDependencyLoader] private void load() { + Width = BUTTON_WIDTH; + ButtonContent.Child = new FillFlowContainer { X = -10f, diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs index da4b3e9602..87d50213ee 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs @@ -269,12 +269,13 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue AvailablePools = { BindTarget = availablePools }, SelectedPool = { BindTarget = selectedPool } }, - new BeginQueueingButton(200) + new BeginQueueingButton { DarkerColour = colours.Blue2, LighterColour = colours.Blue1, Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, + Width = 200, SelectedPool = { BindTarget = selectedPool }, Action = () => { @@ -308,12 +309,13 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue { State = { Value = Visibility.Visible }, }, - new ShearedButton(200) + new ShearedButton { DarkerColour = colours.Red3, LighterColour = colours.Red4, Anchor = Anchor.Centre, Origin = Anchor.Centre, + Width = 200, Text = "Stop queueing", Action = () => client.MatchmakingLeaveQueue().FireAndForget() } @@ -430,11 +432,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue { public readonly IBindable SelectedPool = new Bindable(); - public BeginQueueingButton(float? width = null) - : base(width) - { - } - protected override void LoadComplete() { base.LoadComplete(); @@ -445,11 +442,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue private partial class SelectionButton : ShearedButton, IKeyBindingHandler { - protected SelectionButton(float? width = null, float height = DEFAULT_HEIGHT) - : base(width, height) - { - } - public bool OnPressed(KeyBindingPressEvent e) { if (e.Action == GlobalAction.Select && !e.Repeat) diff --git a/osu.Game/Screens/OnlinePlay/Playlists/AddToPlaylistFooterButton.cs b/osu.Game/Screens/OnlinePlay/Playlists/AddToPlaylistFooterButton.cs index 1d8dcf37ab..622b87503f 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/AddToPlaylistFooterButton.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/AddToPlaylistFooterButton.cs @@ -13,14 +13,11 @@ namespace osu.Game.Screens.OnlinePlay.Playlists { public partial class AddToPlaylistFooterButton : ShearedButton { - public AddToPlaylistFooterButton() - : base(width: 220) - { - } - [BackgroundDependencyLoader] private void load(OsuColour colours) { + Width = 220; + DarkerColour = colours.Blue3; LighterColour = colours.Blue1; diff --git a/osu.Game/Screens/Select/BeatmapDetailsArea.Header.cs b/osu.Game/Screens/Select/BeatmapDetailsArea.Header.cs index fd6437d1a9..b20254a35c 100644 --- a/osu.Game/Screens/Select/BeatmapDetailsArea.Header.cs +++ b/osu.Game/Screens/Select/BeatmapDetailsArea.Header.cs @@ -76,6 +76,7 @@ namespace osu.Game.Screens.Select { Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, + AutoSizeAxes = Axes.X, Text = UserInterfaceStrings.SelectedMods, Height = 30f, // Eyeballed to make spacing match. Because shear is silly and implemented in different ways between dropdown and button. diff --git a/osu.Game/Screens/Select/FilterControl.ScopedBeatmapSetDisplay.cs b/osu.Game/Screens/Select/FilterControl.ScopedBeatmapSetDisplay.cs index 78dfb163ad..040081605f 100644 --- a/osu.Game/Screens/Select/FilterControl.ScopedBeatmapSetDisplay.cs +++ b/osu.Game/Screens/Select/FilterControl.ScopedBeatmapSetDisplay.cs @@ -73,10 +73,11 @@ namespace osu.Game.Screens.Select Colour = colourProvider.Background6, Padding = new MarginPadding { Right = 80, Vertical = 5 } }, - new ShearedButton(80) + new ShearedButton { Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, + Width = 80, Text = CommonStrings.Back, RelativeSizeAxes = Axes.Y, Height = 1, diff --git a/osu.Game/Screens/Select/FilterControl.cs b/osu.Game/Screens/Select/FilterControl.cs index 7473a21531..4867e7de8c 100644 --- a/osu.Game/Screens/Select/FilterControl.cs +++ b/osu.Game/Screens/Select/FilterControl.cs @@ -151,6 +151,7 @@ namespace osu.Game.Screens.Select { Anchor = Anchor.Centre, Origin = Anchor.Centre, + AutoSizeAxes = Axes.X, Text = UserInterfaceStrings.ShowConverts, Height = 30f, },