Merge branch 'master' into add-tutorial

This commit is contained in:
Dean Herbert
2022-04-29 11:25:17 +09:00
19 changed files with 278 additions and 9 deletions

View File

@ -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)
}, },

View File

@ -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());
});
}
}
}

View File

@ -4,6 +4,8 @@
#nullable enable #nullable enable
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
@ -31,6 +33,9 @@ namespace osu.Game.Graphics.UserInterfaceV2
private Color4 enabledColour; private Color4 enabledColour;
private Color4 disabledColour; private Color4 disabledColour;
private Sample? sampleChecked;
private Sample? sampleUnchecked;
public SwitchButton() public SwitchButton()
{ {
Size = new Vector2(45, 20); Size = new Vector2(45, 20);
@ -70,13 +75,16 @@ namespace osu.Game.Graphics.UserInterfaceV2
} }
[BackgroundDependencyLoader(true)] [BackgroundDependencyLoader(true)]
private void load(OverlayColourProvider? colourProvider, OsuColour colours) private void load(OverlayColourProvider? colourProvider, OsuColour colours, AudioManager audio)
{ {
enabledColour = colourProvider?.Highlight1 ?? colours.BlueDark; enabledColour = colourProvider?.Highlight1 ?? colours.BlueDark;
disabledColour = colourProvider?.Background3 ?? colours.Gray3; disabledColour = colourProvider?.Background3 ?? colours.Gray3;
switchContainer.Colour = enabledColour; switchContainer.Colour = enabledColour;
fill.Colour = disabledColour; fill.Colour = disabledColour;
sampleChecked = audio.Samples.Get(@"UI/check-on");
sampleUnchecked = audio.Samples.Get(@"UI/check-off");
} }
protected override void LoadComplete() protected override void LoadComplete()
@ -107,6 +115,16 @@ namespace osu.Game.Graphics.UserInterfaceV2
base.OnHoverLost(e); base.OnHoverLost(e);
} }
protected override void OnUserChange(bool value)
{
base.OnUserChange(value);
if (value)
sampleChecked?.Play();
else
sampleUnchecked?.Play();
}
private void updateBorder() private void updateBorder()
{ {
circularContainer.TransformBorderTo((Current.Value ? enabledColour : disabledColour).Lighten(IsHovered ? 0.3f : 0)); circularContainer.TransformBorderTo((Current.Value ? enabledColour : disabledColour).Lighten(IsHovered ? 0.3f : 0));

View File

@ -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&#39;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}";
} }
} }

View File

@ -72,7 +72,8 @@ namespace osu.Game.Overlays.BeatmapListing
Size = new Vector2(12), Size = new Vector2(12),
Icon = getIconForCardSize(Value) Icon = getIconForCardSize(Value)
} }
} },
new HoverClickSounds(HoverSampleSet.TabSelect)
}; };
} }

View File

@ -33,6 +33,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

View 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();
}
}
}

View File

@ -61,7 +61,8 @@ namespace osu.Game.Overlays
{ {
typeof(ScreenWelcome), typeof(ScreenWelcome),
typeof(ScreenBeatmaps), typeof(ScreenBeatmaps),
typeof(ScreenUIScale) typeof(ScreenUIScale),
typeof(ScreenBehaviour),
}; };
private Container stackContainer = null!; private Container stackContainer = null!;

View File

@ -149,7 +149,7 @@ namespace osu.Game.Overlays
} }
}); });
AddInternal(new HoverClickSounds()); AddInternal(new HoverClickSounds(HoverSampleSet.TabSelect));
} }
protected override void LoadComplete() protected override void LoadComplete()

View File

@ -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();
} }
} }

View File

@ -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)
} }

View File

@ -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" }

View File

@ -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" }

View File

@ -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" },

View File

@ -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),
}, },

View File

@ -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;

View File

@ -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);
} }

View File

@ -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())),

View File

@ -109,7 +109,7 @@ namespace osu.Game.Screens.Menu
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
Children = new Drawable[] Children = new Drawable[]
{ {
logoBounceContainer = new Container logoBounceContainer = new DragContainer
{ {
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
Children = new Drawable[] Children = new Drawable[]
@ -402,5 +402,26 @@ namespace osu.Game.Screens.Menu
impactContainer.ScaleTo(0.96f); impactContainer.ScaleTo(0.96f);
impactContainer.ScaleTo(1.12f, 250); impactContainer.ScaleTo(1.12f, 250);
} }
private class DragContainer : Container
{
protected override bool OnDragStart(DragStartEvent e) => true;
protected override void OnDrag(DragEvent e)
{
Vector2 change = e.MousePosition - e.MouseDownPosition;
// Diminish the drag distance as we go further to simulate "rubber band" feeling.
change *= change.Length <= 0 ? 0 : MathF.Pow(change.Length, 0.6f) / change.Length;
this.MoveTo(change);
}
protected override void OnDragEnd(DragEndEvent e)
{
this.MoveTo(Vector2.Zero, 800, Easing.OutElastic);
base.OnDragEnd(e);
}
}
} }
} }