1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 11:42:56 +08:00

Merge branch 'master' into no-more-sample-control-points-info

This commit is contained in:
Dan Balasescu 2021-09-02 18:09:05 +09:00 committed by GitHub
commit 6c649b7bbe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 724 additions and 397 deletions

View File

@ -10,7 +10,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup Label="Package References"> <ItemGroup Label="Package References">
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" /> <PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
<PackageReference Include="NUnit" Version="3.13.2" /> <PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" /> <PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" /> <PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />

View File

@ -10,7 +10,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup Label="Package References"> <ItemGroup Label="Package References">
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" /> <PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
<PackageReference Include="NUnit" Version="3.13.2" /> <PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" /> <PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" /> <PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />

View File

@ -10,7 +10,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup Label="Package References"> <ItemGroup Label="Package References">
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" /> <PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
<PackageReference Include="NUnit" Version="3.13.2" /> <PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" /> <PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" /> <PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />

View File

@ -10,7 +10,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup Label="Package References"> <ItemGroup Label="Package References">
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" /> <PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
<PackageReference Include="NUnit" Version="3.13.2" /> <PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" /> <PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" /> <PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />

View File

@ -7,7 +7,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.13.0" /> <PackageReference Include="BenchmarkDotNet" Version="0.13.1" />
<PackageReference Include="nunit" Version="3.13.2" /> <PackageReference Include="nunit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" /> <PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
</ItemGroup> </ItemGroup>

View File

@ -2,7 +2,7 @@
<Import Project="..\osu.TestProject.props" /> <Import Project="..\osu.TestProject.props" />
<ItemGroup Label="Package References"> <ItemGroup Label="Package References">
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" /> <PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
<PackageReference Include="NUnit" Version="3.13.2" /> <PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" /> <PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" /> <PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />

View File

@ -2,7 +2,7 @@
<Import Project="..\osu.TestProject.props" /> <Import Project="..\osu.TestProject.props" />
<ItemGroup Label="Package References"> <ItemGroup Label="Package References">
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" /> <PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
<PackageReference Include="NUnit" Version="3.13.2" /> <PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" /> <PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" /> <PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />

View File

@ -37,12 +37,11 @@ namespace osu.Game.Rulesets.Mania.UI
public override void PlayAnimation() public override void PlayAnimation()
{ {
base.PlayAnimation();
switch (Result) switch (Result)
{ {
case HitResult.None: case HitResult.None:
case HitResult.Miss: case HitResult.Miss:
base.PlayAnimation();
break; break;
default: default:
@ -52,6 +51,8 @@ namespace osu.Game.Rulesets.Mania.UI
this.Delay(50) this.Delay(50)
.ScaleTo(0.75f, 250) .ScaleTo(0.75f, 250)
.FadeOut(200); .FadeOut(200);
// osu!mania uses a custom fade length, so the base call is intentionally omitted.
break; break;
} }
} }

View File

@ -2,7 +2,7 @@
<Import Project="..\osu.TestProject.props" /> <Import Project="..\osu.TestProject.props" />
<ItemGroup Label="Package References"> <ItemGroup Label="Package References">
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" /> <PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
<PackageReference Include="Moq" Version="4.16.1" /> <PackageReference Include="Moq" Version="4.16.1" />
<PackageReference Include="NUnit" Version="3.13.2" /> <PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" /> <PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />

View File

@ -74,10 +74,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
public override void PlayAnimation() public override void PlayAnimation()
{ {
base.PlayAnimation();
if (Result != HitResult.Miss) if (Result != HitResult.Miss)
JudgementText.ScaleTo(new Vector2(0.8f, 1)).Then().ScaleTo(new Vector2(1.2f, 1), 1800, Easing.OutQuint); {
JudgementText
.ScaleTo(new Vector2(0.8f, 1))
.ScaleTo(new Vector2(1.2f, 1), 1800, Easing.OutQuint);
}
base.PlayAnimation();
} }
} }
} }

View File

@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default
pathVersion.BindValueChanged(_ => Refresh()); pathVersion.BindValueChanged(_ => Refresh());
accentColour = drawableObject.AccentColour.GetBoundCopy(); accentColour = drawableObject.AccentColour.GetBoundCopy();
accentColour.BindValueChanged(accent => updateAccentColour(skin, accent.NewValue), true); accentColour.BindValueChanged(accent => AccentColour = GetBodyAccentColour(skin, accent.NewValue), true);
config?.BindWith(OsuRulesetSetting.SnakingInSliders, SnakingIn); config?.BindWith(OsuRulesetSetting.SnakingInSliders, SnakingIn);
config?.BindWith(OsuRulesetSetting.SnakingOutSliders, configSnakingOut); config?.BindWith(OsuRulesetSetting.SnakingOutSliders, configSnakingOut);
@ -62,7 +62,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default
} }
} }
private void updateAccentColour(ISkinSource skin, Color4 defaultAccentColour) protected virtual Color4 GetBodyAccentColour(ISkinSource skin, Color4 hitObjectAccentColour) =>
=> AccentColour = skin.GetConfig<OsuSkinColour, Color4>(OsuSkinColour.SliderTrackOverride)?.Value ?? defaultAccentColour; skin.GetConfig<OsuSkinColour, Color4>(OsuSkinColour.SliderTrackOverride)?.Value ?? hitObjectAccentColour;
} }
} }

View File

@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default
/// <summary> /// <summary>
/// A <see cref="SliderBody"/> which changes its curve depending on the snaking progress. /// A <see cref="SliderBody"/> which changes its curve depending on the snaking progress.
/// </summary> /// </summary>
public class SnakingSliderBody : SliderBody, ISliderProgress public abstract class SnakingSliderBody : SliderBody, ISliderProgress
{ {
public readonly List<Vector2> CurrentCurve = new List<Vector2>(); public readonly List<Vector2> CurrentCurve = new List<Vector2>();

View File

@ -5,6 +5,7 @@ using System;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Skinning.Default; using osu.Game.Rulesets.Osu.Skinning.Default;
using osu.Game.Skinning;
using osu.Game.Utils; using osu.Game.Utils;
using osuTK.Graphics; using osuTK.Graphics;
@ -14,6 +15,12 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
{ {
protected override DrawableSliderPath CreateSliderPath() => new LegacyDrawableSliderPath(); protected override DrawableSliderPath CreateSliderPath() => new LegacyDrawableSliderPath();
protected override Color4 GetBodyAccentColour(ISkinSource skin, Color4 hitObjectAccentColour)
{
// legacy skins use a constant value for slider track alpha, regardless of the source colour.
return base.GetBodyAccentColour(skin, hitObjectAccentColour).Opacity(0.7f);
}
private class LegacyDrawableSliderPath : DrawableSliderPath private class LegacyDrawableSliderPath : DrawableSliderPath
{ {
private const float shadow_portion = 1 - (OsuLegacySkinTransformer.LEGACY_CIRCLE_RADIUS / OsuHitObject.OBJECT_RADIUS); private const float shadow_portion = 1 - (OsuLegacySkinTransformer.LEGACY_CIRCLE_RADIUS / OsuHitObject.OBJECT_RADIUS);
@ -22,8 +29,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
// Roughly matches osu!stable's slider border portions. // Roughly matches osu!stable's slider border portions.
=> base.CalculatedBorderPortion * 0.77f; => base.CalculatedBorderPortion * 0.77f;
public new Color4 AccentColour => new Color4(base.AccentColour.R, base.AccentColour.G, base.AccentColour.B, 0.7f);
protected override Color4 ColourAt(float position) protected override Color4 ColourAt(float position)
{ {
float realBorderPortion = shadow_portion + CalculatedBorderPortion; float realBorderPortion = shadow_portion + CalculatedBorderPortion;

View File

@ -2,7 +2,7 @@
<Import Project="..\osu.TestProject.props" /> <Import Project="..\osu.TestProject.props" />
<ItemGroup Label="Package References"> <ItemGroup Label="Package References">
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" /> <PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
<PackageReference Include="NUnit" Version="3.13.2" /> <PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" /> <PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" /> <PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />

View File

@ -3,6 +3,7 @@
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Taiko.UI namespace osu.Game.Rulesets.Taiko.UI
{ {
@ -16,5 +17,26 @@ namespace osu.Game.Rulesets.Taiko.UI
this.MoveToY(-100, 500); this.MoveToY(-100, 500);
base.ApplyHitAnimations(); base.ApplyHitAnimations();
} }
protected override Drawable CreateDefaultJudgement(HitResult result) => new TaikoJudgementPiece(result);
private class TaikoJudgementPiece : DefaultJudgementPiece
{
public TaikoJudgementPiece(HitResult result)
: base(result)
{
}
public override void PlayAnimation()
{
if (Result != HitResult.Miss)
{
JudgementText.ScaleTo(0.9f);
JudgementText.ScaleTo(1, 500, Easing.OutElastic);
}
base.PlayAnimation();
}
}
} }
} }

View File

@ -0,0 +1,100 @@
// 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;
using System.Globalization;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Graphics.UserInterfaceV2;
using osu.Game.Screens.Edit;
using osu.Game.Screens.Edit.Setup;
using osuTK.Input;
namespace osu.Game.Tests.Visual.Editing
{
public class TestSceneDesignSection : OsuManualInputManagerTestScene
{
private TestDesignSection designSection;
private EditorBeatmap editorBeatmap { get; set; }
[SetUpSteps]
public void SetUp()
{
AddStep("create blank beatmap", () => editorBeatmap = new EditorBeatmap(new Beatmap()));
AddStep("create section", () => Child = new DependencyProvidingContainer
{
RelativeSizeAxes = Axes.Both,
CachedDependencies = new (Type, object)[]
{
(typeof(EditorBeatmap), editorBeatmap)
},
Child = designSection = new TestDesignSection()
});
}
[Test]
public void TestCountdownOff()
{
AddStep("turn countdown off", () => designSection.EnableCountdown.Current.Value = false);
AddAssert("beatmap has correct type", () => editorBeatmap.BeatmapInfo.Countdown == CountdownType.None);
AddUntilStep("other controls hidden", () => !designSection.CountdownSettings.IsPresent);
}
[Test]
public void TestCountdownOn()
{
AddStep("turn countdown on", () => designSection.EnableCountdown.Current.Value = true);
AddAssert("beatmap has correct type", () => editorBeatmap.BeatmapInfo.Countdown == CountdownType.Normal);
AddUntilStep("other controls shown", () => designSection.CountdownSettings.IsPresent);
AddStep("change countdown speed", () => designSection.CountdownSpeed.Current.Value = CountdownType.DoubleSpeed);
AddAssert("beatmap has correct type", () => editorBeatmap.BeatmapInfo.Countdown == CountdownType.DoubleSpeed);
AddUntilStep("other controls still shown", () => designSection.CountdownSettings.IsPresent);
}
[Test]
public void TestCountdownOffset()
{
AddStep("turn countdown on", () => designSection.EnableCountdown.Current.Value = true);
AddAssert("beatmap has correct type", () => editorBeatmap.BeatmapInfo.Countdown == CountdownType.Normal);
checkOffsetAfter("1", 1);
checkOffsetAfter(string.Empty, 0);
checkOffsetAfter("123", 123);
checkOffsetAfter("0", 0);
}
private void checkOffsetAfter(string userInput, int expectedFinalValue)
{
AddStep("click text box", () =>
{
var textBox = designSection.CountdownOffset.ChildrenOfType<TextBox>().Single();
InputManager.MoveMouseTo(textBox);
InputManager.Click(MouseButton.Left);
});
AddStep("set offset text", () => designSection.CountdownOffset.Current.Value = userInput);
AddStep("commit text", () => InputManager.Key(Key.Enter));
AddAssert($"displayed value is {expectedFinalValue}", () => designSection.CountdownOffset.Current.Value == expectedFinalValue.ToString(CultureInfo.InvariantCulture));
AddAssert($"beatmap value is {expectedFinalValue}", () => editorBeatmap.BeatmapInfo.CountdownOffset == expectedFinalValue);
}
private class TestDesignSection : DesignSection
{
public new LabelledSwitchButton EnableCountdown => base.EnableCountdown;
public new FillFlowContainer CountdownSettings => base.CountdownSettings;
public new LabelledEnumDropdown<CountdownType> CountdownSpeed => base.CountdownSpeed;
public new LabelledNumberBox CountdownOffset => base.CountdownOffset;
}
}
}

View File

@ -529,7 +529,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("invoke on back button", () => multiplayerScreen.OnBackButton()); AddStep("invoke on back button", () => multiplayerScreen.OnBackButton());
AddAssert("mod overlay is hidden", () => this.ChildrenOfType<LocalPlayerModSelectOverlay>().Single().State.Value == Visibility.Hidden); AddAssert("mod overlay is hidden", () => this.ChildrenOfType<UserModSelectOverlay>().Single().State.Value == Visibility.Hidden);
AddAssert("dialog overlay is hidden", () => DialogOverlay.State.Value == Visibility.Hidden); AddAssert("dialog overlay is hidden", () => DialogOverlay.State.Value == Visibility.Hidden);

View File

@ -323,6 +323,71 @@ namespace osu.Game.Tests.Visual.Navigation
AddWaitStep("wait two frames", 2); AddWaitStep("wait two frames", 2);
} }
[Test]
public void TestOverlayClosing()
{
// use now playing overlay for "overlay -> background" drag case
// since most overlays use a scroll container that absorbs on mouse down
NowPlayingOverlay nowPlayingOverlay = null;
AddStep("enter menu", () => InputManager.Key(Key.Enter));
AddStep("get and press now playing hotkey", () =>
{
nowPlayingOverlay = Game.ChildrenOfType<NowPlayingOverlay>().Single();
InputManager.Key(Key.F6);
});
// drag tests
// background -> toolbar
AddStep("move cursor to background", () => InputManager.MoveMouseTo(Game.ScreenSpaceDrawQuad.BottomRight));
AddStep("press left mouse button", () => InputManager.PressButton(MouseButton.Left));
AddStep("move cursor to toolbar", () => InputManager.MoveMouseTo(Game.Toolbar.ScreenSpaceDrawQuad.Centre));
AddStep("release left mouse button", () => InputManager.ReleaseButton(MouseButton.Left));
AddAssert("now playing is hidden", () => nowPlayingOverlay.State.Value == Visibility.Hidden);
AddStep("press now playing hotkey", () => InputManager.Key(Key.F6));
// toolbar -> background
AddStep("press left mouse button", () => InputManager.PressButton(MouseButton.Left));
AddStep("move cursor to background", () => InputManager.MoveMouseTo(Game.ScreenSpaceDrawQuad.BottomRight));
AddStep("release left mouse button", () => InputManager.ReleaseButton(MouseButton.Left));
AddAssert("now playing is still visible", () => nowPlayingOverlay.State.Value == Visibility.Visible);
// background -> overlay
AddStep("press left mouse button", () => InputManager.PressButton(MouseButton.Left));
AddStep("move cursor to now playing overlay", () => InputManager.MoveMouseTo(nowPlayingOverlay.ScreenSpaceDrawQuad.Centre));
AddStep("release left mouse button", () => InputManager.ReleaseButton(MouseButton.Left));
AddAssert("now playing is still visible", () => nowPlayingOverlay.State.Value == Visibility.Visible);
// overlay -> background
AddStep("press left mouse button", () => InputManager.PressButton(MouseButton.Left));
AddStep("move cursor to background", () => InputManager.MoveMouseTo(Game.ScreenSpaceDrawQuad.BottomRight));
AddStep("release left mouse button", () => InputManager.ReleaseButton(MouseButton.Left));
AddAssert("now playing is still visible", () => nowPlayingOverlay.State.Value == Visibility.Visible);
// background -> background
AddStep("press left mouse button", () => InputManager.PressButton(MouseButton.Left));
AddStep("move cursor to left", () => InputManager.MoveMouseTo(Game.ScreenSpaceDrawQuad.BottomLeft));
AddStep("release left mouse button", () => InputManager.ReleaseButton(MouseButton.Left));
AddAssert("now playing is hidden", () => nowPlayingOverlay.State.Value == Visibility.Hidden);
AddStep("press now playing hotkey", () => InputManager.Key(Key.F6));
// click tests
// toolbar
AddStep("move cursor to toolbar", () => InputManager.MoveMouseTo(Game.Toolbar.ScreenSpaceDrawQuad.Centre));
AddStep("click left mouse button", () => InputManager.Click(MouseButton.Left));
AddAssert("now playing is still visible", () => nowPlayingOverlay.State.Value == Visibility.Visible);
// background
AddStep("move cursor to background", () => InputManager.MoveMouseTo(Game.ScreenSpaceDrawQuad.BottomRight));
AddStep("click left mouse button", () => InputManager.Click(MouseButton.Left));
AddAssert("now playing is hidden", () => nowPlayingOverlay.State.Value == Visibility.Hidden);
}
private void pushEscape() => private void pushEscape() =>
AddStep("Press escape", () => InputManager.Key(Key.Escape)); AddStep("Press escape", () => InputManager.Key(Key.Escape));

View File

@ -422,7 +422,7 @@ namespace osu.Game.Tests.Visual.UserInterface
}; };
} }
private class TestModSelectOverlay : LocalPlayerModSelectOverlay private class TestModSelectOverlay : UserModSelectOverlay
{ {
public new Bindable<IReadOnlyList<Mod>> SelectedMods => base.SelectedMods; public new Bindable<IReadOnlyList<Mod>> SelectedMods => base.SelectedMods;

View File

@ -151,7 +151,7 @@ namespace osu.Game.Tests.Visual.UserInterface
AddUntilStep("wait for ready", () => modSelect.State.Value == Visibility.Visible && modSelect.ButtonsLoaded); AddUntilStep("wait for ready", () => modSelect.State.Value == Visibility.Visible && modSelect.ButtonsLoaded);
} }
private class TestModSelectOverlay : LocalPlayerModSelectOverlay private class TestModSelectOverlay : UserModSelectOverlay
{ {
public new VisibilityContainer ModSettingsContainer => base.ModSettingsContainer; public new VisibilityContainer ModSettingsContainer => base.ModSettingsContainer;
public new TriangleButton CustomiseButton => base.CustomiseButton; public new TriangleButton CustomiseButton => base.CustomiseButton;

View File

@ -0,0 +1,25 @@
// 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 NUnit.Framework;
using osu.Framework.Graphics;
using osu.Game.Screens.Menu;
namespace osu.Game.Tests.Visual.UserInterface
{
public class TestSceneOsuLogo : OsuTestScene
{
[Test]
public void TestBasic()
{
AddStep("Add logo", () =>
{
Child = new OsuLogo
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
};
});
}
}
}

View File

@ -3,7 +3,7 @@
<ItemGroup Label="Package References"> <ItemGroup Label="Package References">
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" /> <PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="DeepEqual" Version="2.0.0" /> <PackageReference Include="DeepEqual" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
<PackageReference Include="NUnit" Version="3.13.2" /> <PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" /> <PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" /> <PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />

View File

@ -5,7 +5,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup Label="Package References"> <ItemGroup Label="Package References">
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" /> <PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
<PackageReference Include="NUnit" Version="3.13.2" /> <PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" /> <PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
</ItemGroup> </ItemGroup>

View File

@ -153,6 +153,11 @@ namespace osu.Game.Beatmaps
if (!storage.Exists(cache_database_name)) if (!storage.Exists(cache_database_name))
return false; return false;
if (string.IsNullOrEmpty(beatmap.MD5Hash)
&& string.IsNullOrEmpty(beatmap.Path)
&& beatmap.OnlineBeatmapID == null)
return false;
try try
{ {
using (var db = new SqliteConnection(storage.GetDatabaseConnectionString("online"))) using (var db = new SqliteConnection(storage.GetDatabaseConnectionString("online")))

View File

@ -1,6 +1,8 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using System.ComponentModel;
namespace osu.Game.Beatmaps namespace osu.Game.Beatmaps
{ {
/// <summary> /// <summary>
@ -9,8 +11,14 @@ namespace osu.Game.Beatmaps
public enum CountdownType public enum CountdownType
{ {
None = 0, None = 0,
[Description("Normal")]
Normal = 1, Normal = 1,
[Description("Half speed")]
HalfSpeed = 2, HalfSpeed = 2,
[Description("Double speed")]
DoubleSpeed = 3 DoubleSpeed = 3
} }
} }

View File

@ -16,7 +16,6 @@ using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osuTK; using osuTK;
@ -24,7 +23,7 @@ using osuTK.Graphics;
namespace osu.Game.Beatmaps.Drawables namespace osu.Game.Beatmaps.Drawables
{ {
public class DifficultyIcon : CompositeDrawable, IHasCustomTooltip public class DifficultyIcon : CompositeDrawable, IHasCustomTooltip<DifficultyIconTooltipContent>
{ {
private readonly Container iconContainer; private readonly Container iconContainer;
@ -127,9 +126,9 @@ namespace osu.Game.Beatmaps.Drawables
difficultyBindable.BindValueChanged(difficulty => background.Colour = colours.ForStarDifficulty(difficulty.NewValue.Stars)); difficultyBindable.BindValueChanged(difficulty => background.Colour = colours.ForStarDifficulty(difficulty.NewValue.Stars));
} }
public ITooltip GetCustomTooltip() => new DifficultyIconTooltip(); ITooltip<DifficultyIconTooltipContent> IHasCustomTooltip<DifficultyIconTooltipContent>.GetCustomTooltip() => new DifficultyIconTooltip();
public object TooltipContent => shouldShowTooltip ? new DifficultyIconTooltipContent(beatmap, difficultyBindable) : null; DifficultyIconTooltipContent IHasCustomTooltip<DifficultyIconTooltipContent>.TooltipContent => shouldShowTooltip ? new DifficultyIconTooltipContent(beatmap, difficultyBindable) : null;
private class DifficultyRetriever : Component private class DifficultyRetriever : Component
{ {
@ -173,113 +172,5 @@ namespace osu.Game.Beatmaps.Drawables
difficultyCancellation?.Cancel(); difficultyCancellation?.Cancel();
} }
} }
private class DifficultyIconTooltipContent
{
public readonly BeatmapInfo Beatmap;
public readonly IBindable<StarDifficulty> Difficulty;
public DifficultyIconTooltipContent(BeatmapInfo beatmap, IBindable<StarDifficulty> difficulty)
{
Beatmap = beatmap;
Difficulty = difficulty;
}
}
private class DifficultyIconTooltip : VisibilityContainer, ITooltip
{
private readonly OsuSpriteText difficultyName, starRating;
private readonly Box background;
private readonly FillFlowContainer difficultyFlow;
public DifficultyIconTooltip()
{
AutoSizeAxes = Axes.Both;
Masking = true;
CornerRadius = 5;
Children = new Drawable[]
{
background = new Box
{
RelativeSizeAxes = Axes.Both
},
new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
AutoSizeDuration = 200,
AutoSizeEasing = Easing.OutQuint,
Direction = FillDirection.Vertical,
Padding = new MarginPadding(10),
Children = new Drawable[]
{
difficultyName = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Font = OsuFont.GetFont(size: 16, weight: FontWeight.Bold),
},
difficultyFlow = new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Direction = FillDirection.Horizontal,
Children = new Drawable[]
{
starRating = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Font = OsuFont.GetFont(size: 16, weight: FontWeight.Regular),
},
new SpriteIcon
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Margin = new MarginPadding { Left = 4 },
Icon = FontAwesome.Solid.Star,
Size = new Vector2(12),
},
}
}
}
}
};
}
[Resolved]
private OsuColour colours { get; set; }
[BackgroundDependencyLoader]
private void load()
{
background.Colour = colours.Gray3;
}
private readonly IBindable<StarDifficulty> starDifficulty = new Bindable<StarDifficulty>();
public void SetContent(object content)
{
if (!(content is DifficultyIconTooltipContent iconContent))
return;
difficultyName.Text = iconContent.Beatmap.Version;
starDifficulty.UnbindAll();
starDifficulty.BindTo(iconContent.Difficulty);
starDifficulty.BindValueChanged(difficulty =>
{
starRating.Text = $"{difficulty.NewValue.Stars:0.##}";
difficultyFlow.Colour = colours.ForStarDifficulty(difficulty.NewValue.Stars);
}, true);
}
public void Move(Vector2 pos) => Position = pos;
protected override void PopIn() => this.FadeIn(200, Easing.OutQuint);
protected override void PopOut() => this.FadeOut(200, Easing.OutQuint);
}
} }
} }

View File

@ -0,0 +1,121 @@
// 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.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osuTK;
namespace osu.Game.Beatmaps.Drawables
{
internal class DifficultyIconTooltip : VisibilityContainer, ITooltip<DifficultyIconTooltipContent>
{
private readonly OsuSpriteText difficultyName, starRating;
private readonly Box background;
private readonly FillFlowContainer difficultyFlow;
public DifficultyIconTooltip()
{
AutoSizeAxes = Axes.Both;
Masking = true;
CornerRadius = 5;
Children = new Drawable[]
{
background = new Box
{
RelativeSizeAxes = Axes.Both
},
new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
AutoSizeDuration = 200,
AutoSizeEasing = Easing.OutQuint,
Direction = FillDirection.Vertical,
Padding = new MarginPadding(10),
Children = new Drawable[]
{
difficultyName = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Font = OsuFont.GetFont(size: 16, weight: FontWeight.Bold),
},
difficultyFlow = new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Direction = FillDirection.Horizontal,
Children = new Drawable[]
{
starRating = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Font = OsuFont.GetFont(size: 16, weight: FontWeight.Regular),
},
new SpriteIcon
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Margin = new MarginPadding { Left = 4 },
Icon = FontAwesome.Solid.Star,
Size = new Vector2(12),
},
}
}
}
}
};
}
[Resolved]
private OsuColour colours { get; set; }
[BackgroundDependencyLoader]
private void load()
{
background.Colour = colours.Gray3;
}
private readonly IBindable<StarDifficulty> starDifficulty = new Bindable<StarDifficulty>();
public void SetContent(DifficultyIconTooltipContent content)
{
difficultyName.Text = content.Beatmap.Version;
starDifficulty.UnbindAll();
starDifficulty.BindTo(content.Difficulty);
starDifficulty.BindValueChanged(difficulty =>
{
starRating.Text = $"{difficulty.NewValue.Stars:0.##}";
difficultyFlow.Colour = colours.ForStarDifficulty(difficulty.NewValue.Stars);
}, true);
}
public void Move(Vector2 pos) => Position = pos;
protected override void PopIn() => this.FadeIn(200, Easing.OutQuint);
protected override void PopOut() => this.FadeOut(200, Easing.OutQuint);
}
internal class DifficultyIconTooltipContent
{
public readonly BeatmapInfo Beatmap;
public readonly IBindable<StarDifficulty> Difficulty;
public DifficultyIconTooltipContent(BeatmapInfo beatmap, IBindable<StarDifficulty> difficulty)
{
Beatmap = beatmap;
Difficulty = difficulty;
}
}
}

View File

@ -153,7 +153,7 @@ namespace osu.Game.Graphics.Backgrounds
TriangleParticle newParticle = parts[i]; TriangleParticle newParticle = parts[i];
// Scale moved distance by the size of the triangle. Smaller triangles should move more slowly. // Scale moved distance by the size of the triangle. Smaller triangles should move more slowly.
newParticle.Position.Y += parts[i].Scale * movedDistance; newParticle.Position.Y += Math.Max(0.5f, parts[i].Scale) * movedDistance;
newParticle.Colour.A = adjustedAlpha; newParticle.Colour.A = adjustedAlpha;
parts[i] = newParticle; parts[i] = newParticle;

View File

@ -10,7 +10,7 @@ using osu.Game.Utils;
namespace osu.Game.Graphics namespace osu.Game.Graphics
{ {
public class DrawableDate : OsuSpriteText, IHasCustomTooltip public class DrawableDate : OsuSpriteText, IHasCustomTooltip<DateTimeOffset>
{ {
private DateTimeOffset date; private DateTimeOffset date;
@ -75,8 +75,8 @@ namespace osu.Game.Graphics
private void updateTime() => Text = Format(); private void updateTime() => Text = Format();
public ITooltip GetCustomTooltip() => new DateTooltip(); public ITooltip<DateTimeOffset> GetCustomTooltip() => new DateTooltip();
public object TooltipContent => Date; public DateTimeOffset TooltipContent => Date;
} }
} }

View File

@ -0,0 +1,12 @@
// 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.Game.Graphics.UserInterface;
namespace osu.Game.Graphics.UserInterfaceV2
{
public class LabelledNumberBox : LabelledTextBox
{
protected override OsuTextBox CreateTextBox() => new OsuNumberBox();
}
}

View File

@ -104,6 +104,8 @@ namespace osu.Game
protected Container ScreenOffsetContainer { get; private set; } protected Container ScreenOffsetContainer { get; private set; }
private Container overlayOffsetContainer;
[Resolved] [Resolved]
private FrameworkConfigManager frameworkConfig { get; set; } private FrameworkConfigManager frameworkConfig { get; set; }
@ -120,7 +122,7 @@ namespace osu.Game
public virtual StableStorage GetStorageForStableInstall() => null; public virtual StableStorage GetStorageForStableInstall() => null;
public float ToolbarOffset => (Toolbar?.Position.Y ?? 0) + (Toolbar?.DrawHeight ?? 0); private float toolbarOffset => (Toolbar?.Position.Y ?? 0) + (Toolbar?.DrawHeight ?? 0);
private IdleTracker idleTracker; private IdleTracker idleTracker;
@ -158,7 +160,7 @@ namespace osu.Game
private readonly string[] args; private readonly string[] args;
private readonly List<OverlayContainer> overlays = new List<OverlayContainer>(); private readonly List<OsuFocusedOverlayContainer> focusedOverlays = new List<OsuFocusedOverlayContainer>();
private readonly List<OverlayContainer> visibleBlockingOverlays = new List<OverlayContainer>(); private readonly List<OverlayContainer> visibleBlockingOverlays = new List<OverlayContainer>();
@ -193,7 +195,7 @@ namespace osu.Game
/// <param name="hideToolbar">Whether the toolbar should also be hidden.</param> /// <param name="hideToolbar">Whether the toolbar should also be hidden.</param>
public void CloseAllOverlays(bool hideToolbar = true) public void CloseAllOverlays(bool hideToolbar = true)
{ {
foreach (var overlay in overlays) foreach (var overlay in focusedOverlays)
overlay.Hide(); overlay.Hide();
if (hideToolbar) Toolbar.Hide(); if (hideToolbar) Toolbar.Hide();
@ -692,9 +694,16 @@ namespace osu.Game
}, },
} }
}, },
overlayContent = new Container { RelativeSizeAxes = Axes.Both }, overlayOffsetContainer = new Container
rightFloatingOverlayContent = new Container { RelativeSizeAxes = Axes.Both }, {
leftFloatingOverlayContent = new Container { RelativeSizeAxes = Axes.Both }, RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
overlayContent = new Container { RelativeSizeAxes = Axes.Both },
rightFloatingOverlayContent = new Container { RelativeSizeAxes = Axes.Both },
leftFloatingOverlayContent = new Container { RelativeSizeAxes = Axes.Both },
}
},
topMostOverlayContent = new Container { RelativeSizeAxes = Axes.Both }, topMostOverlayContent = new Container { RelativeSizeAxes = Axes.Both },
idleTracker, idleTracker,
new ConfineMouseTracker() new ConfineMouseTracker()
@ -731,7 +740,6 @@ namespace osu.Game
loadComponentSingleFile(Notifications.With(d => loadComponentSingleFile(Notifications.With(d =>
{ {
d.GetToolbarHeight = () => ToolbarOffset;
d.Anchor = Anchor.TopRight; d.Anchor = Anchor.TopRight;
d.Origin = Anchor.TopRight; d.Origin = Anchor.TopRight;
}), rightFloatingOverlayContent.Add, true); }), rightFloatingOverlayContent.Add, true);
@ -757,7 +765,7 @@ namespace osu.Game
loadComponentSingleFile(channelManager = new ChannelManager(), AddInternal, true); loadComponentSingleFile(channelManager = new ChannelManager(), AddInternal, true);
loadComponentSingleFile(chatOverlay = new ChatOverlay(), overlayContent.Add, true); loadComponentSingleFile(chatOverlay = new ChatOverlay(), overlayContent.Add, true);
loadComponentSingleFile(new MessageNotifier(), AddInternal, true); loadComponentSingleFile(new MessageNotifier(), AddInternal, true);
loadComponentSingleFile(Settings = new SettingsOverlay { GetToolbarHeight = () => ToolbarOffset }, leftFloatingOverlayContent.Add, true); loadComponentSingleFile(Settings = new SettingsOverlay(), leftFloatingOverlayContent.Add, true);
var changelogOverlay = loadComponentSingleFile(new ChangelogOverlay(), overlayContent.Add, true); var changelogOverlay = loadComponentSingleFile(new ChangelogOverlay(), overlayContent.Add, true);
loadComponentSingleFile(userProfile = new UserProfileOverlay(), overlayContent.Add, true); loadComponentSingleFile(userProfile = new UserProfileOverlay(), overlayContent.Add, true);
loadComponentSingleFile(beatmapSetOverlay = new BeatmapSetOverlay(), overlayContent.Add, true); loadComponentSingleFile(beatmapSetOverlay = new BeatmapSetOverlay(), overlayContent.Add, true);
@ -766,14 +774,12 @@ namespace osu.Game
loadComponentSingleFile(new LoginOverlay loadComponentSingleFile(new LoginOverlay
{ {
GetToolbarHeight = () => ToolbarOffset,
Anchor = Anchor.TopRight, Anchor = Anchor.TopRight,
Origin = Anchor.TopRight, Origin = Anchor.TopRight,
}, rightFloatingOverlayContent.Add, true); }, rightFloatingOverlayContent.Add, true);
loadComponentSingleFile(new NowPlayingOverlay loadComponentSingleFile(new NowPlayingOverlay
{ {
GetToolbarHeight = () => ToolbarOffset,
Anchor = Anchor.TopRight, Anchor = Anchor.TopRight,
Origin = Anchor.TopRight, Origin = Anchor.TopRight,
}, rightFloatingOverlayContent.Add, true); }, rightFloatingOverlayContent.Add, true);
@ -904,8 +910,8 @@ namespace osu.Game
if (cache) if (cache)
dependencies.CacheAs(component); dependencies.CacheAs(component);
if (component is OverlayContainer overlay) if (component is OsuFocusedOverlayContainer overlay)
overlays.Add(overlay); focusedOverlays.Add(overlay);
// schedule is here to ensure that all component loads are done after LoadComplete is run (and thus all dependencies are cached). // schedule is here to ensure that all component loads are done after LoadComplete is run (and thus all dependencies are cached).
// with some better organisation of LoadComplete to do construction and dependency caching in one step, followed by calls to loadComponentSingleFile, // with some better organisation of LoadComplete to do construction and dependency caching in one step, followed by calls to loadComponentSingleFile,
@ -1013,8 +1019,8 @@ namespace osu.Game
{ {
base.UpdateAfterChildren(); base.UpdateAfterChildren();
ScreenOffsetContainer.Padding = new MarginPadding { Top = ToolbarOffset }; ScreenOffsetContainer.Padding = new MarginPadding { Top = toolbarOffset };
overlayContent.Padding = new MarginPadding { Top = ToolbarOffset }; overlayOffsetContainer.Padding = new MarginPadding { Top = toolbarOffset };
var horizontalOffset = 0f; var horizontalOffset = 0f;

View File

@ -140,12 +140,8 @@ namespace osu.Game.Overlays.Dashboard.Home.News
} }
} }
private class Date : CompositeDrawable, IHasCustomTooltip private class Date : CompositeDrawable, IHasCustomTooltip<DateTimeOffset>
{ {
public ITooltip GetCustomTooltip() => new DateTooltip();
public object TooltipContent => date;
private readonly DateTimeOffset date; private readonly DateTimeOffset date;
public Date(DateTimeOffset date) public Date(DateTimeOffset date)
@ -190,6 +186,10 @@ namespace osu.Game.Overlays.Dashboard.Home.News
} }
}; };
} }
ITooltip<DateTimeOffset> IHasCustomTooltip<DateTimeOffset>.GetCustomTooltip() => new DateTooltip();
DateTimeOffset IHasCustomTooltip<DateTimeOffset>.TooltipContent => date;
} }
} }
} }

View File

@ -67,12 +67,8 @@ namespace osu.Game.Overlays.Dashboard.Home.News
}; };
} }
private class Date : CompositeDrawable, IHasCustomTooltip private class Date : CompositeDrawable, IHasCustomTooltip<DateTimeOffset>
{ {
public ITooltip GetCustomTooltip() => new DateTooltip();
public object TooltipContent => date;
private readonly DateTimeOffset date; private readonly DateTimeOffset date;
public Date(DateTimeOffset date) public Date(DateTimeOffset date)
@ -110,6 +106,10 @@ namespace osu.Game.Overlays.Dashboard.Home.News
t.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Regular); t.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Regular);
}); });
} }
ITooltip<DateTimeOffset> IHasCustomTooltip<DateTimeOffset>.GetCustomTooltip() => new DateTooltip();
DateTimeOffset IHasCustomTooltip<DateTimeOffset>.TooltipContent => date;
} }
} }
} }

View File

@ -10,7 +10,6 @@ using osuTK.Graphics;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Cursor; using osu.Game.Graphics.Cursor;
using System;
namespace osu.Game.Overlays namespace osu.Game.Overlays
{ {
@ -20,11 +19,6 @@ namespace osu.Game.Overlays
private const float transition_time = 400; private const float transition_time = 400;
/// <summary>
/// Provide a source for the toolbar height.
/// </summary>
public Func<float> GetToolbarHeight;
public LoginOverlay() public LoginOverlay()
{ {
AutoSizeAxes = Axes.Both; AutoSizeAxes = Axes.Both;
@ -94,12 +88,5 @@ namespace osu.Game.Overlays
settingsSection.Bounding = false; settingsSection.Bounding = false;
this.FadeOut(transition_time); this.FadeOut(transition_time);
} }
protected override void UpdateAfterChildren()
{
base.UpdateAfterChildren();
Padding = new MarginPadding { Top = GetToolbarHeight?.Invoke() ?? 0 };
}
} }
} }

View File

@ -0,0 +1,117 @@
// 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.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Play.HUD;
using osu.Game.Utils;
using osuTK;
namespace osu.Game.Overlays.Mods
{
public class IncompatibilityDisplayingModButton : ModButton
{
private readonly CompositeDrawable incompatibleIcon;
[Resolved]
private Bindable<IReadOnlyList<Mod>> selectedMods { get; set; }
public IncompatibilityDisplayingModButton(Mod mod)
: base(mod)
{
ButtonContent.Add(incompatibleIcon = new IncompatibleIcon
{
Anchor = Anchor.BottomRight,
Origin = Anchor.Centre,
Position = new Vector2(-13),
});
}
protected override void LoadComplete()
{
base.LoadComplete();
selectedMods.BindValueChanged(_ => Scheduler.AddOnce(updateCompatibility), true);
}
protected override void DisplayMod(Mod mod)
{
base.DisplayMod(mod);
Scheduler.AddOnce(updateCompatibility);
}
private void updateCompatibility()
{
var m = SelectedMod ?? Mods.First();
bool isIncompatible = false;
if (selectedMods.Value.Count > 0 && !selectedMods.Value.Contains(m))
isIncompatible = !ModUtils.CheckCompatibleSet(selectedMods.Value.Append(m));
if (isIncompatible)
incompatibleIcon.Show();
else
incompatibleIcon.Hide();
}
public override ITooltip<Mod> GetCustomTooltip() => new IncompatibilityDisplayingTooltip();
private class IncompatibilityDisplayingTooltip : ModButtonTooltip
{
private readonly OsuSpriteText incompatibleText;
private readonly Bindable<IReadOnlyList<Mod>> incompatibleMods = new Bindable<IReadOnlyList<Mod>>();
[Resolved]
private Bindable<RulesetInfo> ruleset { get; set; }
public IncompatibilityDisplayingTooltip()
{
AddRange(new Drawable[]
{
incompatibleText = new OsuSpriteText
{
Margin = new MarginPadding { Top = 5 },
Font = OsuFont.GetFont(weight: FontWeight.Regular),
Text = "Incompatible with:"
},
new ModDisplay
{
Current = incompatibleMods,
ExpansionMode = ExpansionMode.AlwaysExpanded,
Scale = new Vector2(0.7f)
}
});
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
incompatibleText.Colour = colours.BlueLight;
}
protected override void UpdateDisplay(Mod mod)
{
base.UpdateDisplay(mod);
var incompatibleTypes = mod.IncompatibleMods;
var allMods = ruleset.Value.CreateInstance().GetAllMods();
incompatibleMods.Value = allMods.Where(m => m.GetType() != mod.GetType() && incompatibleTypes.Any(t => t.IsInstanceOfType(m))).ToList();
incompatibleText.Text = incompatibleMods.Value.Any() ? "Incompatible with:" : "Compatible with all mods";
}
}
}
}

View File

@ -11,29 +11,24 @@ using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Cursor;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Utils;
namespace osu.Game.Overlays.Mods namespace osu.Game.Overlays.Mods
{ {
/// <summary> /// <summary>
/// Represents a clickable button which can cycle through one of more mods. /// Represents a clickable button which can cycle through one of more mods.
/// </summary> /// </summary>
public class ModButton : ModButtonEmpty, IHasCustomTooltip public class ModButton : ModButtonEmpty, IHasCustomTooltip<Mod>
{ {
private ModIcon foregroundIcon; private ModIcon foregroundIcon;
private ModIcon backgroundIcon; private ModIcon backgroundIcon;
private readonly SpriteText text; private readonly SpriteText text;
private readonly Container<ModIcon> iconsContainer; private readonly Container<ModIcon> iconsContainer;
private readonly CompositeDrawable incompatibleIcon;
/// <summary> /// <summary>
/// Fired when the selection changes. /// Fired when the selection changes.
@ -48,9 +43,6 @@ namespace osu.Game.Overlays.Mods
// A selected index of -1 means not selected. // A selected index of -1 means not selected.
private int selectedIndex = -1; private int selectedIndex = -1;
[Resolved]
private Bindable<IReadOnlyList<Mod>> selectedMods { get; set; }
/// <summary> /// <summary>
/// Change the selected mod index of this button. /// Change the selected mod index of this button.
/// </summary> /// </summary>
@ -109,7 +101,7 @@ namespace osu.Game.Overlays.Mods
.RotateTo(rotate_angle * direction) .RotateTo(rotate_angle * direction)
.RotateTo(0f, mod_switch_duration, mod_switch_easing); .RotateTo(0f, mod_switch_duration, mod_switch_easing);
Schedule(() => displayMod(newSelection)); Schedule(() => DisplayMod(newSelection));
} }
} }
@ -138,7 +130,8 @@ namespace osu.Game.Overlays.Mods
} }
private Mod mod; private Mod mod;
private readonly Container scaleContainer;
protected readonly Container ButtonContent;
public Mod Mod public Mod Mod
{ {
@ -162,7 +155,7 @@ namespace osu.Game.Overlays.Mods
if (Mods.Length > 0) if (Mods.Length > 0)
{ {
displayMod(Mods[0]); DisplayMod(Mods[0]);
} }
} }
} }
@ -173,13 +166,13 @@ namespace osu.Game.Overlays.Mods
protected override bool OnMouseDown(MouseDownEvent e) protected override bool OnMouseDown(MouseDownEvent e)
{ {
scaleContainer.ScaleTo(0.9f, 800, Easing.Out); ButtonContent.ScaleTo(0.9f, 800, Easing.Out);
return base.OnMouseDown(e); return base.OnMouseDown(e);
} }
protected override void OnMouseUp(MouseUpEvent e) protected override void OnMouseUp(MouseUpEvent e)
{ {
scaleContainer.ScaleTo(1, 500, Easing.OutElastic); ButtonContent.ScaleTo(1, 500, Easing.OutElastic);
// only trigger the event if we are inside the area of the button // only trigger the event if we are inside the area of the button
if (Contains(e.ScreenSpaceMousePosition)) if (Contains(e.ScreenSpaceMousePosition))
@ -238,30 +231,13 @@ namespace osu.Game.Overlays.Mods
public void Deselect() => changeSelectedIndex(-1); public void Deselect() => changeSelectedIndex(-1);
private void displayMod(Mod mod) protected virtual void DisplayMod(Mod mod)
{ {
if (backgroundIcon != null) if (backgroundIcon != null)
backgroundIcon.Mod = foregroundIcon.Mod; backgroundIcon.Mod = foregroundIcon.Mod;
foregroundIcon.Mod = mod; foregroundIcon.Mod = mod;
text.Text = mod.Name; text.Text = mod.Name;
Colour = mod.HasImplementation ? Color4.White : Color4.Gray; Colour = mod.HasImplementation ? Color4.White : Color4.Gray;
Scheduler.AddOnce(updateCompatibility);
}
private void updateCompatibility()
{
var m = SelectedMod ?? Mods.First();
bool isIncompatible = false;
if (selectedMods.Value.Count > 0 && !selectedMods.Value.Contains(m))
isIncompatible = !ModUtils.CheckCompatibleSet(selectedMods.Value.Append(m));
if (isIncompatible)
incompatibleIcon.Show();
else
incompatibleIcon.Hide();
} }
private void createIcons() private void createIcons()
@ -307,7 +283,7 @@ namespace osu.Game.Overlays.Mods
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Children = new Drawable[] Children = new Drawable[]
{ {
scaleContainer = new Container ButtonContent = new Container
{ {
Children = new Drawable[] Children = new Drawable[]
{ {
@ -317,12 +293,6 @@ namespace osu.Game.Overlays.Mods
Origin = Anchor.Centre, Origin = Anchor.Centre,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
}, },
incompatibleIcon = new IncompatibleIcon
{
Origin = Anchor.Centre,
Anchor = Anchor.BottomRight,
Position = new Vector2(-13),
}
}, },
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Origin = Anchor.Centre, Origin = Anchor.Centre,
@ -342,15 +312,8 @@ namespace osu.Game.Overlays.Mods
Mod = mod; Mod = mod;
} }
protected override void LoadComplete() public virtual ITooltip<Mod> GetCustomTooltip() => new ModButtonTooltip();
{
base.LoadComplete();
selectedMods.BindValueChanged(_ => Scheduler.AddOnce(updateCompatibility), true); public Mod TooltipContent => SelectedMod ?? Mods.FirstOrDefault();
}
public ITooltip GetCustomTooltip() => new ModButtonTooltip();
public object TooltipContent => SelectedMod ?? Mods.FirstOrDefault();
} }
} }

View File

@ -1,19 +1,14 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Play.HUD;
using osuTK; using osuTK;
namespace osu.Game.Overlays.Mods namespace osu.Game.Overlays.Mods
@ -22,12 +17,8 @@ namespace osu.Game.Overlays.Mods
{ {
private readonly OsuSpriteText descriptionText; private readonly OsuSpriteText descriptionText;
private readonly Box background; private readonly Box background;
private readonly OsuSpriteText incompatibleText;
private readonly Bindable<IReadOnlyList<Mod>> incompatibleMods = new Bindable<IReadOnlyList<Mod>>(); protected override Container<Drawable> Content { get; }
[Resolved]
private Bindable<RulesetInfo> ruleset { get; set; }
public ModButtonTooltip() public ModButtonTooltip()
{ {
@ -35,13 +26,13 @@ namespace osu.Game.Overlays.Mods
Masking = true; Masking = true;
CornerRadius = 5; CornerRadius = 5;
Children = new Drawable[] InternalChildren = new Drawable[]
{ {
background = new Box background = new Box
{ {
RelativeSizeAxes = Axes.Both RelativeSizeAxes = Axes.Both
}, },
new FillFlowContainer Content = new FillFlowContainer
{ {
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
Direction = FillDirection.Vertical, Direction = FillDirection.Vertical,
@ -51,19 +42,7 @@ namespace osu.Game.Overlays.Mods
descriptionText = new OsuSpriteText descriptionText = new OsuSpriteText
{ {
Font = OsuFont.GetFont(weight: FontWeight.Regular), Font = OsuFont.GetFont(weight: FontWeight.Regular),
Margin = new MarginPadding { Bottom = 5 }
}, },
incompatibleText = new OsuSpriteText
{
Font = OsuFont.GetFont(weight: FontWeight.Regular),
Text = "Incompatible with:"
},
new ModDisplay
{
Current = incompatibleMods,
ExpansionMode = ExpansionMode.AlwaysExpanded,
Scale = new Vector2(0.7f)
}
} }
}, },
}; };
@ -74,7 +53,6 @@ namespace osu.Game.Overlays.Mods
{ {
background.Colour = colours.Gray3; background.Colour = colours.Gray3;
descriptionText.Colour = colours.BlueLighter; descriptionText.Colour = colours.BlueLighter;
incompatibleText.Colour = colours.BlueLight;
} }
protected override void PopIn() => this.FadeIn(200, Easing.OutQuint); protected override void PopIn() => this.FadeIn(200, Easing.OutQuint);
@ -84,19 +62,17 @@ namespace osu.Game.Overlays.Mods
public void SetContent(Mod mod) public void SetContent(Mod mod)
{ {
if (mod.Equals(lastMod)) return; if (mod.Equals(lastMod))
return;
lastMod = mod; lastMod = mod;
UpdateDisplay(mod);
}
protected virtual void UpdateDisplay(Mod mod)
{
descriptionText.Text = mod.Description; descriptionText.Text = mod.Description;
var incompatibleTypes = mod.IncompatibleMods;
var allMods = ruleset.Value.CreateInstance().GetAllMods();
incompatibleMods.Value = allMods.Where(m => m.GetType() != mod.GetType() && incompatibleTypes.Any(t => t.IsInstanceOfType(m))).ToList();
incompatibleText.Text = !incompatibleMods.Value.Any() ? "Compatible with all mods" : "Incompatible with:";
} }
public void Move(Vector2 pos) => Position = pos; public void Move(Vector2 pos) => Position = pos;

View File

@ -51,14 +51,14 @@ namespace osu.Game.Overlays.Mods
if (m == null) if (m == null)
return new ModButtonEmpty(); return new ModButtonEmpty();
return new ModButton(m) return CreateModButton(m).With(b =>
{ {
SelectionChanged = mod => b.SelectionChanged = mod =>
{ {
ModButtonStateChanged(mod); ModButtonStateChanged(mod);
Action?.Invoke(mod); Action?.Invoke(mod);
}, };
}; });
}).ToArray(); }).ToArray();
modsLoadCts?.Cancel(); modsLoadCts?.Cancel();
@ -247,6 +247,8 @@ namespace osu.Game.Overlays.Mods
Text = text Text = text
}; };
protected virtual ModButton CreateModButton(Mod mod) => new ModButton(mod);
/// <summary> /// <summary>
/// Play out all remaining animations immediately to leave mods in a good (final) state. /// Play out all remaining animations immediately to leave mods in a good (final) state.
/// </summary> /// </summary>

View File

@ -5,7 +5,7 @@ using osu.Game.Rulesets.Mods;
namespace osu.Game.Overlays.Mods namespace osu.Game.Overlays.Mods
{ {
public class LocalPlayerModSelectOverlay : ModSelectOverlay public class UserModSelectOverlay : ModSelectOverlay
{ {
protected override void OnModSelected(Mod mod) protected override void OnModSelected(Mod mod)
{ {
@ -14,5 +14,17 @@ namespace osu.Game.Overlays.Mods
foreach (var section in ModSectionsContainer.Children) foreach (var section in ModSectionsContainer.Children)
section.DeselectTypes(mod.IncompatibleMods, true, mod); section.DeselectTypes(mod.IncompatibleMods, true, mod);
} }
protected override ModSection CreateModSection(ModType type) => new UserModSection(type);
private class UserModSection : ModSection
{
public UserModSection(ModType type)
: base(type)
{
}
protected override ModButton CreateModButton(Mod mod) => new IncompatibilityDisplayingModButton(mod);
}
} }
} }

View File

@ -123,12 +123,8 @@ namespace osu.Game.Overlays.News
main.AddText(post.Author, t => t.Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold)); main.AddText(post.Author, t => t.Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold));
} }
private class DateContainer : CircularContainer, IHasCustomTooltip private class DateContainer : CircularContainer, IHasCustomTooltip<DateTimeOffset>
{ {
public ITooltip GetCustomTooltip() => new DateTooltip();
public object TooltipContent => date;
private readonly DateTimeOffset date; private readonly DateTimeOffset date;
public DateContainer(DateTimeOffset date) public DateContainer(DateTimeOffset date)
@ -162,6 +158,10 @@ namespace osu.Game.Overlays.News
} }
protected override bool OnClick(ClickEvent e) => true; // Protects the NewsCard from clicks while hovering DateContainer protected override bool OnClick(ClickEvent e) => true; // Protects the NewsCard from clicks while hovering DateContainer
ITooltip<DateTimeOffset> IHasCustomTooltip<DateTimeOffset>.GetCustomTooltip() => new DateTooltip();
DateTimeOffset IHasCustomTooltip<DateTimeOffset>.TooltipContent => date;
} }
} }
} }

View File

@ -8,7 +8,6 @@ using osu.Framework.Graphics.Containers;
using osu.Game.Overlays.Notifications; using osu.Game.Overlays.Notifications;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using System;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Localisation; using osu.Framework.Localisation;
@ -30,11 +29,6 @@ namespace osu.Game.Overlays
private FlowContainer<NotificationSection> sections; private FlowContainer<NotificationSection> sections;
/// <summary>
/// Provide a source for the toolbar height.
/// </summary>
public Func<float> GetToolbarHeight;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
@ -168,12 +162,5 @@ namespace osu.Game.Overlays
updateCounts(); updateCounts();
} }
protected override void UpdateAfterChildren()
{
base.UpdateAfterChildren();
Padding = new MarginPadding { Top = GetToolbarHeight?.Invoke() ?? 0 };
}
} }
} }

View File

@ -55,11 +55,6 @@ namespace osu.Game.Overlays
protected override string PopInSampleName => "UI/now-playing-pop-in"; protected override string PopInSampleName => "UI/now-playing-pop-in";
protected override string PopOutSampleName => "UI/now-playing-pop-out"; protected override string PopOutSampleName => "UI/now-playing-pop-out";
/// <summary>
/// Provide a source for the toolbar height.
/// </summary>
public Func<float> GetToolbarHeight;
[Resolved] [Resolved]
private MusicController musicController { get; set; } private MusicController musicController { get; set; }
@ -246,7 +241,6 @@ namespace osu.Game.Overlays
base.UpdateAfterChildren(); base.UpdateAfterChildren();
Height = dragContainer.Height; Height = dragContainer.Height;
dragContainer.Padding = new MarginPadding { Top = GetToolbarHeight?.Invoke() ?? 0 };
} }
protected override void Update() protected override void Update()

View File

@ -8,7 +8,6 @@ using Humanizer;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Extensions.LocalisationExtensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Localisation;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Resources.Localisation.Web; using osu.Game.Resources.Localisation.Web;
@ -61,40 +60,14 @@ namespace osu.Game.Overlays.Profile.Header.Components
placeholder.FadeIn(FADE_DURATION, Easing.Out); placeholder.FadeIn(FADE_DURATION, Easing.Out);
} }
protected override object GetTooltipContent(int index, int rank) protected override UserGraphTooltipContent GetTooltipContent(int index, int rank)
{ {
var days = ranked_days - index + 1; var days = ranked_days - index + 1;
return new TooltipDisplayContent return new UserGraphTooltipContent(
{ UsersStrings.ShowRankGlobalSimple,
Rank = rank.ToLocalisableString("\\##,##0"), rank.ToLocalisableString("\\##,##0"),
Time = days == 0 ? "now" : $"{"day".ToQuantity(days)} ago" days == 0 ? "now" : $"{"day".ToQuantity(days)} ago");
};
}
protected override UserGraphTooltip GetTooltip() => new RankGraphTooltip();
private class RankGraphTooltip : UserGraphTooltip
{
public RankGraphTooltip()
: base(UsersStrings.ShowRankGlobalSimple)
{
}
public override void SetContent(object content)
{
if (!(content is TooltipDisplayContent info))
return;
Counter.Text = info.Rank;
BottomText.Text = info.Time;
}
}
private class TooltipDisplayContent
{
public LocalisableString Rank;
public string Time;
} }
} }
} }

View File

@ -28,43 +28,10 @@ namespace osu.Game.Overlays.Profile.Sections.Historical
protected override float GetDataPointHeight(long playCount) => playCount; protected override float GetDataPointHeight(long playCount) => playCount;
protected override UserGraphTooltip GetTooltip() => new HistoryGraphTooltip(tooltipCounterName); protected override UserGraphTooltipContent GetTooltipContent(DateTime date, long playCount) =>
new UserGraphTooltipContent(
protected override object GetTooltipContent(DateTime date, long playCount) tooltipCounterName,
{ playCount.ToLocalisableString("N0"),
return new TooltipDisplayContent date.ToLocalisableString("MMMM yyyy"));
{
Name = tooltipCounterName,
Count = playCount.ToLocalisableString("N0"),
Date = date.ToLocalisableString("MMMM yyyy")
};
}
protected class HistoryGraphTooltip : UserGraphTooltip
{
private readonly LocalisableString tooltipCounterName;
public HistoryGraphTooltip(LocalisableString tooltipCounterName)
: base(tooltipCounterName)
{
this.tooltipCounterName = tooltipCounterName;
}
public override void SetContent(object content)
{
if (!(content is TooltipDisplayContent info) || info.Name != tooltipCounterName)
return;
Counter.Text = info.Count;
BottomText.Text = info.Date;
}
}
private class TooltipDisplayContent
{
public LocalisableString Name;
public LocalisableString Count;
public LocalisableString Date;
}
} }
} }

View File

@ -24,7 +24,7 @@ namespace osu.Game.Overlays.Profile
/// </summary> /// </summary>
/// <typeparam name="TKey">Type of data to be used for X-axis of the graph.</typeparam> /// <typeparam name="TKey">Type of data to be used for X-axis of the graph.</typeparam>
/// <typeparam name="TValue">Type of data to be used for Y-axis of the graph.</typeparam> /// <typeparam name="TValue">Type of data to be used for Y-axis of the graph.</typeparam>
public abstract class UserGraph<TKey, TValue> : Container, IHasCustomTooltip public abstract class UserGraph<TKey, TValue> : Container, IHasCustomTooltip<UserGraphTooltipContent>
{ {
protected const float FADE_DURATION = 150; protected const float FADE_DURATION = 150;
@ -118,11 +118,9 @@ namespace osu.Game.Overlays.Profile
protected virtual void ShowGraph() => graph.FadeIn(FADE_DURATION, Easing.Out); protected virtual void ShowGraph() => graph.FadeIn(FADE_DURATION, Easing.Out);
protected virtual void HideGraph() => graph.FadeOut(FADE_DURATION, Easing.Out); protected virtual void HideGraph() => graph.FadeOut(FADE_DURATION, Easing.Out);
public ITooltip GetCustomTooltip() => GetTooltip(); public ITooltip<UserGraphTooltipContent> GetCustomTooltip() => new UserGraphTooltip();
protected abstract UserGraphTooltip GetTooltip(); public UserGraphTooltipContent TooltipContent
public object TooltipContent
{ {
get get
{ {
@ -134,7 +132,7 @@ namespace osu.Game.Overlays.Profile
} }
} }
protected abstract object GetTooltipContent(TKey key, TValue value); protected abstract UserGraphTooltipContent GetTooltipContent(TKey key, TValue value);
protected class UserLineGraph : LineGraph protected class UserLineGraph : LineGraph
{ {
@ -207,12 +205,12 @@ namespace osu.Game.Overlays.Profile
} }
} }
protected abstract class UserGraphTooltip : VisibilityContainer, ITooltip private class UserGraphTooltip : VisibilityContainer, ITooltip<UserGraphTooltipContent>
{ {
protected readonly OsuSpriteText Counter, BottomText; protected readonly OsuSpriteText Label, Counter, BottomText;
private readonly Box background; private readonly Box background;
protected UserGraphTooltip(LocalisableString tooltipCounterName) public UserGraphTooltip()
{ {
AutoSizeAxes = Axes.Both; AutoSizeAxes = Axes.Both;
Masking = true; Masking = true;
@ -238,10 +236,9 @@ namespace osu.Game.Overlays.Profile
Spacing = new Vector2(3, 0), Spacing = new Vector2(3, 0),
Children = new Drawable[] Children = new Drawable[]
{ {
new OsuSpriteText Label = new OsuSpriteText
{ {
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold), Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold),
Text = tooltipCounterName
}, },
Counter = new OsuSpriteText Counter = new OsuSpriteText
{ {
@ -268,7 +265,12 @@ namespace osu.Game.Overlays.Profile
background.Colour = colours.Gray1; background.Colour = colours.Gray1;
} }
public abstract void SetContent(object content); public void SetContent(UserGraphTooltipContent content)
{
Label.Text = content.Name;
Counter.Text = content.Count;
BottomText.Text = content.Time;
}
private bool instantMove = true; private bool instantMove = true;
@ -292,4 +294,19 @@ namespace osu.Game.Overlays.Profile
protected override void PopOut() => this.FadeOut(200, Easing.OutQuint); protected override void PopOut() => this.FadeOut(200, Easing.OutQuint);
} }
} }
public class UserGraphTooltipContent
{
// todo: could use init-only properties on C# 9 which read better than a constructor.
public LocalisableString Name { get; }
public LocalisableString Count { get; }
public LocalisableString Time { get; }
public UserGraphTooltipContent(LocalisableString name, LocalisableString count, LocalisableString time)
{
Name = name;
Count = count;
Time = time;
}
}
} }

View File

@ -54,11 +54,6 @@ namespace osu.Game.Overlays
protected override string PopInSampleName => "UI/settings-pop-in"; protected override string PopInSampleName => "UI/settings-pop-in";
/// <summary>
/// Provide a source for the toolbar height.
/// </summary>
public Func<float> GetToolbarHeight;
private readonly bool showSidebar; private readonly bool showSidebar;
private LoadingLayer loading; private LoadingLayer loading;
@ -193,7 +188,6 @@ namespace osu.Game.Overlays
base.UpdateAfterChildren(); base.UpdateAfterChildren();
ContentContainer.Margin = new MarginPadding { Left = Sidebar?.DrawWidth ?? 0 }; ContentContainer.Margin = new MarginPadding { Left = Sidebar?.DrawWidth ?? 0 };
Padding = new MarginPadding { Top = GetToolbarHeight?.Invoke() ?? 0 };
} }
private const double fade_in_duration = 1000; private const double fade_in_duration = 1000;

View File

@ -18,7 +18,7 @@ using osu.Game.Input.Bindings;
namespace osu.Game.Overlays.Toolbar namespace osu.Game.Overlays.Toolbar
{ {
public class Toolbar : VisibilityContainer, IKeyBindingHandler<GlobalAction> public class Toolbar : OverlayContainer, IKeyBindingHandler<GlobalAction>
{ {
public const float HEIGHT = 40; public const float HEIGHT = 40;
public const float TOOLTIP_HEIGHT = 30; public const float TOOLTIP_HEIGHT = 30;
@ -41,6 +41,8 @@ namespace osu.Game.Overlays.Toolbar
// Toolbar and its components need keyboard input even when hidden. // Toolbar and its components need keyboard input even when hidden.
public override bool PropagateNonPositionalInputSubTree => true; public override bool PropagateNonPositionalInputSubTree => true;
protected override bool BlockScrollInput => false;
public Toolbar() public Toolbar()
{ {
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;

View File

@ -47,6 +47,13 @@ namespace osu.Game.Rulesets.Judgements
}; };
} }
/// <summary>
/// Plays the default animation for this judgement piece.
/// </summary>
/// <remarks>
/// The base implementation only handles fade (for all result types) and misses.
/// Individual rulesets are recommended to implement their appropriate hit animations.
/// </remarks>
public virtual void PlayAnimation() public virtual void PlayAnimation()
{ {
switch (Result) switch (Result)
@ -60,12 +67,6 @@ namespace osu.Game.Rulesets.Judgements
this.RotateTo(0); this.RotateTo(0);
this.RotateTo(40, 800, Easing.InQuint); this.RotateTo(40, 800, Easing.InQuint);
break;
default:
this.ScaleTo(0.9f);
this.ScaleTo(1, 500, Easing.OutElastic);
break; break;
} }

View File

@ -1,14 +1,27 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using System;
using System.Globalization;
using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Game.Beatmaps;
using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Graphics.UserInterfaceV2;
using osuTK;
namespace osu.Game.Screens.Edit.Setup namespace osu.Game.Screens.Edit.Setup
{ {
internal class DesignSection : SetupSection internal class DesignSection : SetupSection
{ {
protected LabelledSwitchButton EnableCountdown;
protected FillFlowContainer CountdownSettings;
protected LabelledEnumDropdown<CountdownType> CountdownSpeed;
protected LabelledNumberBox CountdownOffset;
private LabelledSwitchButton widescreenSupport; private LabelledSwitchButton widescreenSupport;
private LabelledSwitchButton epilepsyWarning; private LabelledSwitchButton epilepsyWarning;
private LabelledSwitchButton letterboxDuringBreaks; private LabelledSwitchButton letterboxDuringBreaks;
@ -20,6 +33,35 @@ namespace osu.Game.Screens.Edit.Setup
{ {
Children = new[] Children = new[]
{ {
EnableCountdown = new LabelledSwitchButton
{
Label = "Enable countdown",
Current = { Value = Beatmap.BeatmapInfo.Countdown != CountdownType.None },
Description = "If enabled, an \"Are you ready? 3, 2, 1, GO!\" countdown will be inserted at the beginning of the beatmap, assuming there is enough time to do so."
},
CountdownSettings = new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Spacing = new Vector2(10),
Direction = FillDirection.Vertical,
Children = new Drawable[]
{
CountdownSpeed = new LabelledEnumDropdown<CountdownType>
{
Label = "Countdown speed",
Current = { Value = Beatmap.BeatmapInfo.Countdown != CountdownType.None ? Beatmap.BeatmapInfo.Countdown : CountdownType.Normal },
Items = Enum.GetValues(typeof(CountdownType)).Cast<CountdownType>().Where(type => type != CountdownType.None)
},
CountdownOffset = new LabelledNumberBox
{
Label = "Countdown offset",
Current = { Value = Beatmap.BeatmapInfo.CountdownOffset.ToString() },
Description = "If the countdown sounds off-time, use this to make it appear one or more beats early.",
}
}
},
Empty(),
widescreenSupport = new LabelledSwitchButton widescreenSupport = new LabelledSwitchButton
{ {
Label = "Widescreen support", Label = "Widescreen support",
@ -45,13 +87,31 @@ namespace osu.Game.Screens.Edit.Setup
{ {
base.LoadComplete(); base.LoadComplete();
EnableCountdown.Current.BindValueChanged(_ => updateCountdownSettingsVisibility(), true);
EnableCountdown.Current.BindValueChanged(_ => updateBeatmap());
CountdownSpeed.Current.BindValueChanged(_ => updateBeatmap());
CountdownOffset.OnCommit += (_, __) => onOffsetCommitted();
widescreenSupport.Current.BindValueChanged(_ => updateBeatmap()); widescreenSupport.Current.BindValueChanged(_ => updateBeatmap());
epilepsyWarning.Current.BindValueChanged(_ => updateBeatmap()); epilepsyWarning.Current.BindValueChanged(_ => updateBeatmap());
letterboxDuringBreaks.Current.BindValueChanged(_ => updateBeatmap()); letterboxDuringBreaks.Current.BindValueChanged(_ => updateBeatmap());
} }
private void updateCountdownSettingsVisibility() => CountdownSettings.FadeTo(EnableCountdown.Current.Value ? 1 : 0);
private void onOffsetCommitted()
{
updateBeatmap();
// update displayed text to ensure parsed value matches display (i.e. if empty string was provided).
CountdownOffset.Current.Value = Beatmap.BeatmapInfo.CountdownOffset.ToString(CultureInfo.InvariantCulture);
}
private void updateBeatmap() private void updateBeatmap()
{ {
Beatmap.BeatmapInfo.Countdown = EnableCountdown.Current.Value ? CountdownSpeed.Current.Value : CountdownType.None;
Beatmap.BeatmapInfo.CountdownOffset = int.TryParse(CountdownOffset.Current.Value, NumberStyles.None, CultureInfo.InvariantCulture, out int offset) ? offset : 0;
Beatmap.BeatmapInfo.WidescreenStoryboard = widescreenSupport.Current.Value; Beatmap.BeatmapInfo.WidescreenStoryboard = widescreenSupport.Current.Value;
Beatmap.BeatmapInfo.EpilepsyWarning = epilepsyWarning.Current.Value; Beatmap.BeatmapInfo.EpilepsyWarning = epilepsyWarning.Current.Value;
Beatmap.BeatmapInfo.LetterboxInBreaks = letterboxDuringBreaks.Current.Value; Beatmap.BeatmapInfo.LetterboxInBreaks = letterboxDuringBreaks.Current.Value;

View File

@ -25,7 +25,7 @@ namespace osu.Game.Screens.Edit.Setup
{ {
AddRange(new Drawable[] AddRange(new Drawable[]
{ {
sections = new SectionsContainer<SetupSection> sections = new SetupScreenSectionsContainer
{ {
FixedHeader = header, FixedHeader = header,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
@ -40,5 +40,19 @@ namespace osu.Game.Screens.Edit.Setup
}, },
}); });
} }
private class SetupScreenSectionsContainer : SectionsContainer<SetupSection>
{
protected override UserTrackingScrollContainer CreateScrollContainer()
{
var scrollContainer = base.CreateScrollContainer();
// Workaround for masking issues (see https://github.com/ppy/osu-framework/issues/1675#issuecomment-910023157)
// Note that this actually causes the full scroll range to be reduced by 2px at the bottom, but it's not really noticeable.
scrollContainer.Margin = new MarginPadding { Top = 2 };
return scrollContainer;
}
}
} }
} }

View File

@ -429,10 +429,6 @@ namespace osu.Game.Screens.OnlinePlay.Match
/// <param name="room">The room to change the settings of.</param> /// <param name="room">The room to change the settings of.</param>
protected abstract RoomSettingsOverlay CreateRoomSettingsOverlay(Room room); protected abstract RoomSettingsOverlay CreateRoomSettingsOverlay(Room room);
private class UserModSelectOverlay : LocalPlayerModSelectOverlay
{
}
public class UserModSelectButton : PurpleTriangleButton public class UserModSelectButton : PurpleTriangleButton
{ {
} }

View File

@ -152,7 +152,7 @@ namespace osu.Game.Screens.OnlinePlay
return base.OnExiting(next); return base.OnExiting(next);
} }
protected override ModSelectOverlay CreateModSelectOverlay() => new LocalPlayerModSelectOverlay protected override ModSelectOverlay CreateModSelectOverlay() => new UserModSelectOverlay
{ {
IsValidMod = IsValidMod IsValidMod = IsValidMod
}; };

View File

@ -315,7 +315,7 @@ namespace osu.Game.Screens.Select
(new FooterButtonOptions(), BeatmapOptions) (new FooterButtonOptions(), BeatmapOptions)
}; };
protected virtual ModSelectOverlay CreateModSelectOverlay() => new LocalPlayerModSelectOverlay(); protected virtual ModSelectOverlay CreateModSelectOverlay() => new UserModSelectOverlay();
protected virtual void ApplyFilterToCarousel(FilterCriteria criteria) protected virtual void ApplyFilterToCarousel(FilterCriteria criteria)
{ {

View File

@ -20,12 +20,12 @@
<ItemGroup Label="Package References"> <ItemGroup Label="Package References">
<PackageReference Include="AutoMapper" Version="10.1.1" /> <PackageReference Include="AutoMapper" Version="10.1.1" />
<PackageReference Include="DiffPlex" Version="1.7.0" /> <PackageReference Include="DiffPlex" Version="1.7.0" />
<PackageReference Include="HtmlAgilityPack" Version="1.11.34" /> <PackageReference Include="HtmlAgilityPack" Version="1.11.36" />
<PackageReference Include="Humanizer" Version="2.11.10" /> <PackageReference Include="Humanizer" Version="2.11.10" />
<PackageReference Include="MessagePack" Version="2.3.75" /> <PackageReference Include="MessagePack" Version="2.3.75" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="5.0.8" /> <PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="5.0.9" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="5.0.8" /> <PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="5.0.9" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="5.0.8" /> <PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="5.0.9" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
@ -38,7 +38,7 @@
<PackageReference Include="Realm" Version="10.3.0" /> <PackageReference Include="Realm" Version="10.3.0" />
<PackageReference Include="ppy.osu.Framework" Version="2021.830.0" /> <PackageReference Include="ppy.osu.Framework" Version="2021.830.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.827.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2021.827.0" />
<PackageReference Include="Sentry" Version="3.8.3" /> <PackageReference Include="Sentry" Version="3.9.0" />
<PackageReference Include="SharpCompress" Version="0.28.3" /> <PackageReference Include="SharpCompress" Version="0.28.3" />
<PackageReference Include="NUnit" Version="3.13.2" /> <PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" /> <PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />

View File

@ -98,7 +98,7 @@
<PackageReference Include="NUnit" Version="3.13.2" /> <PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="SharpRaven" Version="2.4.0" /> <PackageReference Include="SharpRaven" Version="2.4.0" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" /> <PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageReference Include="ppy.osu.Framework.NativeLibs" Version="2021.115.0" ExcludeAssets="all" /> <PackageReference Include="ppy.osu.Framework.NativeLibs" Version="2021.805.0" ExcludeAssets="all" />
<PackageReference Include="Realm" Version="10.3.0" /> <PackageReference Include="Realm" Version="10.3.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>