mirror of
https://github.com/ppy/osu.git
synced 2025-01-28 06:03:08 +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
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
|
ClassicDefault = false,
|
||||||
LabelText = "Snaking out sliders",
|
LabelText = "Snaking out sliders",
|
||||||
Current = config.GetBindable<bool>(OsuRulesetSetting.SnakingOutSliders)
|
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>
|
/// <summary>
|
||||||
/// "Click to resume first-run setup at any point"
|
/// "Click to resume first-run setup at any point"
|
||||||
/// </summary>
|
/// </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>
|
/// <summary>
|
||||||
/// "First-run setup"
|
/// "First-run setup"
|
||||||
@ -48,6 +49,31 @@ osu! is a very configurable game, and diving straight into the settings can some
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString UIScaleDescription => new TranslatableString(getKey(@"ui_scale_description"), @"The size of the osu! user interface can be adjusted to your liking.");
|
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}";
|
private static string getKey(string key) => $@"{prefix}:{key}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ namespace osu.Game.Overlays.FirstRunSetup
|
|||||||
new OsuScrollContainer(Direction.Vertical)
|
new OsuScrollContainer(Direction.Vertical)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
ScrollbarOverlapsContent = false,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new OsuSpriteText
|
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 =
|
private readonly Type[] steps =
|
||||||
{
|
{
|
||||||
typeof(ScreenWelcome),
|
typeof(ScreenWelcome),
|
||||||
typeof(ScreenUIScale)
|
typeof(ScreenUIScale),
|
||||||
|
typeof(ScreenBehaviour),
|
||||||
};
|
};
|
||||||
|
|
||||||
private Container stackContainer = null!;
|
private Container stackContainer = null!;
|
||||||
|
@ -9,5 +9,20 @@ namespace osu.Game.Overlays.Settings
|
|||||||
public interface ISettingsItem : IDrawable, IDisposable
|
public interface ISettingsItem : IDrawable, IDisposable
|
||||||
{
|
{
|
||||||
event Action SettingChanged;
|
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
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
|
ClassicDefault = false,
|
||||||
LabelText = GameplaySettingsStrings.AlwaysPlayFirstComboBreak,
|
LabelText = GameplaySettingsStrings.AlwaysPlayFirstComboBreak,
|
||||||
Current = config.GetBindable<bool>(OsuSetting.AlwaysPlayFirstComboBreak)
|
Current = config.GetBindable<bool>(OsuSetting.AlwaysPlayFirstComboBreak)
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
|
|||||||
{
|
{
|
||||||
new SettingsEnumDropdown<ScoringMode>
|
new SettingsEnumDropdown<ScoringMode>
|
||||||
{
|
{
|
||||||
|
ClassicDefault = ScoringMode.Classic,
|
||||||
LabelText = GameplaySettingsStrings.ScoreDisplayMode,
|
LabelText = GameplaySettingsStrings.ScoreDisplayMode,
|
||||||
Current = config.GetBindable<ScoringMode>(OsuSetting.ScoreDisplayMode),
|
Current = config.GetBindable<ScoringMode>(OsuSetting.ScoreDisplayMode),
|
||||||
Keywords = new[] { "scoring" }
|
Keywords = new[] { "scoring" }
|
||||||
|
@ -30,6 +30,7 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
|
|||||||
},
|
},
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
|
ClassicDefault = false,
|
||||||
LabelText = GameplaySettingsStrings.ShowHealthDisplayWhenCantFail,
|
LabelText = GameplaySettingsStrings.ShowHealthDisplayWhenCantFail,
|
||||||
Current = config.GetBindable<bool>(OsuSetting.ShowHealthDisplayWhenCantFail),
|
Current = config.GetBindable<bool>(OsuSetting.ShowHealthDisplayWhenCantFail),
|
||||||
Keywords = new[] { "hp", "bar" }
|
Keywords = new[] { "hp", "bar" }
|
||||||
|
@ -37,6 +37,7 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface
|
|||||||
},
|
},
|
||||||
new SettingsSlider<double, TimeSlider>
|
new SettingsSlider<double, TimeSlider>
|
||||||
{
|
{
|
||||||
|
ClassicDefault = 0,
|
||||||
LabelText = UserInterfaceStrings.HoldToConfirmActivationTime,
|
LabelText = UserInterfaceStrings.HoldToConfirmActivationTime,
|
||||||
Current = config.GetBindable<double>(OsuSetting.UIHoldActivationDelay),
|
Current = config.GetBindable<double>(OsuSetting.UIHoldActivationDelay),
|
||||||
Keywords = new[] { @"delay" },
|
Keywords = new[] { @"delay" },
|
||||||
|
@ -32,6 +32,7 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface
|
|||||||
{
|
{
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
|
ClassicDefault = true,
|
||||||
LabelText = UserInterfaceStrings.RightMouseScroll,
|
LabelText = UserInterfaceStrings.RightMouseScroll,
|
||||||
Current = config.GetBindable<bool>(OsuSetting.SongSelectRightMouseScroll),
|
Current = config.GetBindable<bool>(OsuSetting.SongSelectRightMouseScroll),
|
||||||
},
|
},
|
||||||
|
@ -30,6 +30,8 @@ namespace osu.Game.Overlays.Settings
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public object SettingSourceObject { get; internal set; }
|
public object SettingSourceObject { get; internal set; }
|
||||||
|
|
||||||
|
public const string CLASSIC_DEFAULT_SEARCH_TERM = @"has-classic-default";
|
||||||
|
|
||||||
private IHasCurrentValue<T> controlWithCurrent => Control as IHasCurrentValue<T>;
|
private IHasCurrentValue<T> controlWithCurrent => Control as IHasCurrentValue<T>;
|
||||||
|
|
||||||
protected override Container<Drawable> Content => FlowContent;
|
protected override Container<Drawable> Content => FlowContent;
|
||||||
@ -96,7 +98,21 @@ namespace osu.Game.Overlays.Settings
|
|||||||
set => controlWithCurrent.Current = value;
|
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; }
|
public IEnumerable<string> Keywords { get; set; }
|
||||||
|
|
||||||
@ -122,6 +138,32 @@ namespace osu.Game.Overlays.Settings
|
|||||||
|
|
||||||
public event Action SettingChanged;
|
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()
|
protected SettingsItem()
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
@ -58,7 +59,7 @@ namespace osu.Game.Overlays.Settings
|
|||||||
|
|
||||||
public bool FilteringActive { get; set; }
|
public bool FilteringActive { get; set; }
|
||||||
|
|
||||||
[Resolved]
|
[Resolved(canBeNull: true)]
|
||||||
private SettingsPanel settingsPanel { get; set; }
|
private SettingsPanel settingsPanel { get; set; }
|
||||||
|
|
||||||
protected SettingsSection()
|
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);
|
selectedSection.BindValueChanged(_ => updateContentFade(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,7 +153,10 @@ namespace osu.Game.Overlays.Settings
|
|||||||
protected override bool OnClick(ClickEvent e)
|
protected override bool OnClick(ClickEvent e)
|
||||||
{
|
{
|
||||||
if (!isCurrentSection)
|
if (!isCurrentSection)
|
||||||
|
{
|
||||||
|
Debug.Assert(settingsPanel != null);
|
||||||
settingsPanel.SectionsContainer.ScrollTo(this);
|
settingsPanel.SectionsContainer.ScrollTo(this);
|
||||||
|
}
|
||||||
|
|
||||||
return base.OnClick(e);
|
return base.OnClick(e);
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
protected override IEnumerable<SettingsSection> CreateSections() => new SettingsSection[]
|
protected override IEnumerable<SettingsSection> CreateSections() => new SettingsSection[]
|
||||||
{
|
{
|
||||||
|
// This list should be kept in sync with ScreenBehaviour.
|
||||||
new GeneralSection(),
|
new GeneralSection(),
|
||||||
new SkinSection(),
|
new SkinSection(),
|
||||||
new InputSection(createSubPanel(new KeyBindingPanel())),
|
new InputSection(createSubPanel(new KeyBindingPanel())),
|
||||||
|
Loading…
Reference in New Issue
Block a user