mirror of
https://github.com/ppy/osu.git
synced 2025-01-13 15:33:21 +08:00
Merge pull request #17926 from peppy/first-run-behaviour-screen
Add first-run "behaviour" screen to allow users a choice of more familiar UX
This commit is contained in:
commit
7097ce6501
@ -33,6 +33,7 @@ namespace osu.Game.Rulesets.Osu.UI
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
ClassicDefault = false,
|
||||
LabelText = "Snaking out sliders",
|
||||
Current = config.GetBindable<bool>(OsuRulesetSetting.SnakingOutSliders)
|
||||
},
|
||||
|
@ -0,0 +1,24 @@
|
||||
// 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.Screens;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.FirstRunSetup;
|
||||
|
||||
namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
public class TestSceneFirstRunScreenBehaviour : OsuManualInputManagerTestScene
|
||||
{
|
||||
[Cached]
|
||||
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple);
|
||||
|
||||
public TestSceneFirstRunScreenBehaviour()
|
||||
{
|
||||
AddStep("load screen", () =>
|
||||
{
|
||||
Child = new ScreenStack(new ScreenBehaviour());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -17,7 +17,8 @@ namespace osu.Game.Localisation
|
||||
/// <summary>
|
||||
/// "Click to resume first-run setup at any point"
|
||||
/// </summary>
|
||||
public static LocalisableString ClickToResumeFirstRunSetupAtAnyPoint => new TranslatableString(getKey(@"click_to_resume_first_run_setup_at_any_point"), @"Click to resume first-run setup at any point");
|
||||
public static LocalisableString ClickToResumeFirstRunSetupAtAnyPoint =>
|
||||
new TranslatableString(getKey(@"click_to_resume_first_run_setup_at_any_point"), @"Click to resume first-run setup at any point");
|
||||
|
||||
/// <summary>
|
||||
/// "First-run setup"
|
||||
@ -48,6 +49,31 @@ osu! is a very configurable game, and diving straight into the settings can some
|
||||
/// </summary>
|
||||
public static LocalisableString UIScaleDescription => new TranslatableString(getKey(@"ui_scale_description"), @"The size of the osu! user interface can be adjusted to your liking.");
|
||||
|
||||
/// <summary>
|
||||
/// "Behaviour"
|
||||
/// </summary>
|
||||
public static LocalisableString Behaviour => new TranslatableString(getKey(@"behaviour"), @"Behaviour");
|
||||
|
||||
/// <summary>
|
||||
/// "Some new defaults for game behaviours have been implemented, with the aim of improving the game experience and making it more accessible to everyone.
|
||||
///
|
||||
/// We recommend you give the new defaults a try, but if you'd like to have things feel more like classic versions of osu!, you can easily apply some sane defaults below."
|
||||
/// </summary>
|
||||
public static LocalisableString BehaviourDescription => new TranslatableString(getKey(@"behaviour_description"),
|
||||
@"Some new defaults for game behaviours have been implemented, with the aim of improving the game experience and making it more accessible to everyone.
|
||||
|
||||
We recommend you give the new defaults a try, but if you'd like to have things feel more like classic versions of osu!, you can easily apply some sane defaults below.");
|
||||
|
||||
/// <summary>
|
||||
/// "New defaults"
|
||||
/// </summary>
|
||||
public static LocalisableString NewDefaults => new TranslatableString(getKey(@"new_defaults"), @"New defaults");
|
||||
|
||||
/// <summary>
|
||||
/// "Classic defaults"
|
||||
/// </summary>
|
||||
public static LocalisableString ClassicDefaults => new TranslatableString(getKey(@"classic_defaults"), @"Classic defaults");
|
||||
|
||||
private static string getKey(string key) => $@"{prefix}:{key}";
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ namespace osu.Game.Overlays.FirstRunSetup
|
||||
new OsuScrollContainer(Direction.Vertical)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
ScrollbarOverlapsContent = false,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
|
109
osu.Game/Overlays/FirstRunSetup/ScreenBehaviour.cs
Normal file
109
osu.Game/Overlays/FirstRunSetup/ScreenBehaviour.cs
Normal file
@ -0,0 +1,109 @@
|
||||
// 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 System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Localisation;
|
||||
using osu.Game.Overlays.Settings;
|
||||
using osu.Game.Overlays.Settings.Sections;
|
||||
|
||||
namespace osu.Game.Overlays.FirstRunSetup
|
||||
{
|
||||
[LocalisableDescription(typeof(FirstRunSetupOverlayStrings), nameof(FirstRunSetupOverlayStrings.Behaviour))]
|
||||
public class ScreenBehaviour : FirstRunSetupScreen
|
||||
{
|
||||
private SearchContainer<SettingsSection> searchContainer;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Content.Children = new Drawable[]
|
||||
{
|
||||
new OsuTextFlowContainer(cp => cp.Font = OsuFont.Default.With(size: 24))
|
||||
{
|
||||
Text = FirstRunSetupOverlayStrings.BehaviourDescription,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y
|
||||
},
|
||||
new GridContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
ColumnDimensions = new[]
|
||||
{
|
||||
new Dimension(),
|
||||
new Dimension(GridSizeMode.Absolute, 10),
|
||||
new Dimension(),
|
||||
},
|
||||
RowDimensions = new[]
|
||||
{
|
||||
new Dimension(GridSizeMode.AutoSize),
|
||||
},
|
||||
Content = new[]
|
||||
{
|
||||
new[]
|
||||
{
|
||||
new TriangleButton
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
Text = FirstRunSetupOverlayStrings.NewDefaults,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Action = applyStandard,
|
||||
},
|
||||
Empty(),
|
||||
new DangerousTriangleButton
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
Text = FirstRunSetupOverlayStrings.ClassicDefaults,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Action = applyClassic
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
searchContainer = new SearchContainer<SettingsSection>
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Children = new SettingsSection[]
|
||||
{
|
||||
// This list should be kept in sync with SettingsOverlay.
|
||||
new GeneralSection(),
|
||||
new SkinSection(),
|
||||
// InputSection is intentionally omitted for now due to its sub-panel being a pain to set up.
|
||||
new UserInterfaceSection(),
|
||||
new GameplaySection(),
|
||||
new RulesetSection(),
|
||||
new AudioSection(),
|
||||
new GraphicsSection(),
|
||||
new OnlineSection(),
|
||||
new MaintenanceSection(),
|
||||
new DebugSection(),
|
||||
},
|
||||
SearchTerm = SettingsItem<bool>.CLASSIC_DEFAULT_SEARCH_TERM,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void applyClassic()
|
||||
{
|
||||
foreach (var i in searchContainer.ChildrenOfType<ISettingsItem>().Where(s => s.HasClassicDefault))
|
||||
i.ApplyClassicDefault();
|
||||
}
|
||||
|
||||
private void applyStandard()
|
||||
{
|
||||
foreach (var i in searchContainer.ChildrenOfType<ISettingsItem>().Where(s => s.HasClassicDefault))
|
||||
i.ApplyDefault();
|
||||
}
|
||||
}
|
||||
}
|
@ -60,7 +60,8 @@ namespace osu.Game.Overlays
|
||||
private readonly Type[] steps =
|
||||
{
|
||||
typeof(ScreenWelcome),
|
||||
typeof(ScreenUIScale)
|
||||
typeof(ScreenUIScale),
|
||||
typeof(ScreenBehaviour),
|
||||
};
|
||||
|
||||
private Container stackContainer = null!;
|
||||
|
@ -9,5 +9,20 @@ namespace osu.Game.Overlays.Settings
|
||||
public interface ISettingsItem : IDrawable, IDisposable
|
||||
{
|
||||
event Action SettingChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Whether this setting has a classic default (ie. a different default which better aligns with osu-stable expectations).
|
||||
/// </summary>
|
||||
bool HasClassicDefault { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Apply the classic default value of the associated setting. Will throw if <see cref="HasClassicDefault"/> is <c>false</c>.
|
||||
/// </summary>
|
||||
void ApplyClassicDefault();
|
||||
|
||||
/// <summary>
|
||||
/// Apply the default value of the associated setting.
|
||||
/// </summary>
|
||||
void ApplyDefault();
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
ClassicDefault = false,
|
||||
LabelText = GameplaySettingsStrings.AlwaysPlayFirstComboBreak,
|
||||
Current = config.GetBindable<bool>(OsuSetting.AlwaysPlayFirstComboBreak)
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
|
||||
{
|
||||
new SettingsEnumDropdown<ScoringMode>
|
||||
{
|
||||
ClassicDefault = ScoringMode.Classic,
|
||||
LabelText = GameplaySettingsStrings.ScoreDisplayMode,
|
||||
Current = config.GetBindable<ScoringMode>(OsuSetting.ScoreDisplayMode),
|
||||
Keywords = new[] { "scoring" }
|
||||
|
@ -30,6 +30,7 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
ClassicDefault = false,
|
||||
LabelText = GameplaySettingsStrings.ShowHealthDisplayWhenCantFail,
|
||||
Current = config.GetBindable<bool>(OsuSetting.ShowHealthDisplayWhenCantFail),
|
||||
Keywords = new[] { "hp", "bar" }
|
||||
|
@ -37,6 +37,7 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface
|
||||
},
|
||||
new SettingsSlider<double, TimeSlider>
|
||||
{
|
||||
ClassicDefault = 0,
|
||||
LabelText = UserInterfaceStrings.HoldToConfirmActivationTime,
|
||||
Current = config.GetBindable<double>(OsuSetting.UIHoldActivationDelay),
|
||||
Keywords = new[] { @"delay" },
|
||||
|
@ -32,6 +32,7 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface
|
||||
{
|
||||
new SettingsCheckbox
|
||||
{
|
||||
ClassicDefault = true,
|
||||
LabelText = UserInterfaceStrings.RightMouseScroll,
|
||||
Current = config.GetBindable<bool>(OsuSetting.SongSelectRightMouseScroll),
|
||||
},
|
||||
|
@ -30,6 +30,8 @@ namespace osu.Game.Overlays.Settings
|
||||
/// </summary>
|
||||
public object SettingSourceObject { get; internal set; }
|
||||
|
||||
public const string CLASSIC_DEFAULT_SEARCH_TERM = @"has-classic-default";
|
||||
|
||||
private IHasCurrentValue<T> controlWithCurrent => Control as IHasCurrentValue<T>;
|
||||
|
||||
protected override Container<Drawable> Content => FlowContent;
|
||||
@ -96,7 +98,21 @@ namespace osu.Game.Overlays.Settings
|
||||
set => controlWithCurrent.Current = value;
|
||||
}
|
||||
|
||||
public virtual IEnumerable<string> FilterTerms => Keywords == null ? new[] { LabelText.ToString() } : new List<string>(Keywords) { LabelText.ToString() }.ToArray();
|
||||
public virtual IEnumerable<string> FilterTerms
|
||||
{
|
||||
get
|
||||
{
|
||||
var keywords = new List<string>(Keywords ?? Array.Empty<string>())
|
||||
{
|
||||
LabelText.ToString()
|
||||
};
|
||||
|
||||
if (HasClassicDefault)
|
||||
keywords.Add(CLASSIC_DEFAULT_SEARCH_TERM);
|
||||
|
||||
return keywords;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<string> Keywords { get; set; }
|
||||
|
||||
@ -122,6 +138,32 @@ namespace osu.Game.Overlays.Settings
|
||||
|
||||
public event Action SettingChanged;
|
||||
|
||||
private T classicDefault;
|
||||
|
||||
public bool HasClassicDefault { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// A "classic" default value for this setting.
|
||||
/// </summary>
|
||||
public T ClassicDefault
|
||||
{
|
||||
set
|
||||
{
|
||||
classicDefault = value;
|
||||
HasClassicDefault = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplyClassicDefault()
|
||||
{
|
||||
if (!HasClassicDefault)
|
||||
throw new InvalidOperationException($"Cannot apply a classic default to a setting which doesn't have one defined via {nameof(ClassicDefault)}.");
|
||||
|
||||
Current.Value = classicDefault;
|
||||
}
|
||||
|
||||
public void ApplyDefault() => Current.SetDefault();
|
||||
|
||||
protected SettingsItem()
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
@ -58,7 +59,7 @@ namespace osu.Game.Overlays.Settings
|
||||
|
||||
public bool FilteringActive { get; set; }
|
||||
|
||||
[Resolved]
|
||||
[Resolved(canBeNull: true)]
|
||||
private SettingsPanel settingsPanel { get; set; }
|
||||
|
||||
protected SettingsSection()
|
||||
@ -131,7 +132,7 @@ namespace osu.Game.Overlays.Settings
|
||||
},
|
||||
});
|
||||
|
||||
selectedSection = settingsPanel.CurrentSection.GetBoundCopy();
|
||||
selectedSection = settingsPanel?.CurrentSection.GetBoundCopy() ?? new Bindable<SettingsSection>(this);
|
||||
selectedSection.BindValueChanged(_ => updateContentFade(), true);
|
||||
}
|
||||
|
||||
@ -152,7 +153,10 @@ namespace osu.Game.Overlays.Settings
|
||||
protected override bool OnClick(ClickEvent e)
|
||||
{
|
||||
if (!isCurrentSection)
|
||||
{
|
||||
Debug.Assert(settingsPanel != null);
|
||||
settingsPanel.SectionsContainer.ScrollTo(this);
|
||||
}
|
||||
|
||||
return base.OnClick(e);
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ namespace osu.Game.Overlays
|
||||
|
||||
protected override IEnumerable<SettingsSection> CreateSections() => new SettingsSection[]
|
||||
{
|
||||
// This list should be kept in sync with ScreenBehaviour.
|
||||
new GeneralSection(),
|
||||
new SkinSection(),
|
||||
new InputSection(createSubPanel(new KeyBindingPanel())),
|
||||
|
Loading…
Reference in New Issue
Block a user