1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-06 06:57:39 +08:00

Merge remote-tracking branch 'upstream/master' into user-status-wiring

This commit is contained in:
Lucas A 2019-05-14 18:09:58 +02:00
commit 2d966682dc
49 changed files with 728 additions and 568 deletions

View File

@ -57,33 +57,20 @@ namespace osu.Game.Rulesets.Catch.Difficulty
CatchHitObject lastObject = null;
foreach (var hitObject in beatmap.HitObjects.OfType<CatchHitObject>())
// In 2B beatmaps, it is possible that a normal Fruit is placed in the middle of a JuiceStream.
foreach (var hitObject in beatmap.HitObjects
.SelectMany(obj => obj is JuiceStream stream ? stream.NestedHitObjects : new[] { obj })
.Cast<CatchHitObject>()
.OrderBy(x => x.StartTime))
{
if (lastObject == null)
{
lastObject = hitObject;
// We want to only consider fruits that contribute to the combo.
if (hitObject is BananaShower || hitObject is TinyDroplet)
continue;
}
switch (hitObject)
{
// We want to only consider fruits that contribute to the combo. Droplets are addressed as accuracy and spinners are not relevant for "skill" calculations.
case Fruit fruit:
yield return new CatchDifficultyHitObject(fruit, lastObject, clockRate, halfCatchWidth);
if (lastObject != null)
yield return new CatchDifficultyHitObject(hitObject, lastObject, clockRate, halfCatchWidth);
lastObject = hitObject;
break;
case JuiceStream _:
foreach (var nested in hitObject.NestedHitObjects.OfType<CatchHitObject>().Where(o => !(o is TinyDroplet)))
{
yield return new CatchDifficultyHitObject(nested, lastObject, clockRate, halfCatchWidth);
lastObject = nested;
}
break;
}
lastObject = hitObject;
}
}

View File

@ -7,6 +7,7 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Input;
using osu.Framework.Input.Events;
using osu.Framework.MathUtils;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects;
@ -48,7 +49,14 @@ namespace osu.Game.Rulesets.Osu.Mods
protected override bool OnMouseMove(MouseMoveEvent e)
{
FlashlightPosition = e.MousePosition;
const double follow_delay = 120;
var position = FlashlightPosition;
var destination = e.MousePosition;
FlashlightPosition = Interpolation.ValueAt(
MathHelper.Clamp(Clock.ElapsedFrameTime, 0, follow_delay), position, destination, 0, follow_delay, Easing.Out);
return base.OnMouseMove(e);
}

View File

@ -0,0 +1,56 @@
// 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.IO;
using NUnit.Framework;
using osu.Game.Beatmaps.Formats;
using osu.Game.Tests.Resources;
namespace osu.Game.Tests.Beatmaps.Formats
{
[TestFixture]
public class LegacyDecoderTest
{
[Test]
public void TestDecodeComments()
{
var decoder = new LineLoggingDecoder(14);
using (var resStream = TestResources.OpenResource("comments.osu"))
using (var stream = new StreamReader(resStream))
{
decoder.Decode(stream);
Assert.That(decoder.ParsedLines, Has.None.EqualTo("// Combo1: 0, 0, 0"));
Assert.That(decoder.ParsedLines, Has.None.EqualTo("//Combo2: 0, 0, 0"));
Assert.That(decoder.ParsedLines, Has.None.EqualTo(" // Combo3: 0, 0, 0"));
Assert.That(decoder.ParsedLines, Has.One.EqualTo("Combo1: 100, 100, 100 // Comment at end of line"));
}
}
private class LineLoggingDecoder : LegacyDecoder<TestModel>
{
public readonly List<string> ParsedLines = new List<string>();
public LineLoggingDecoder(int version)
: base(version)
{
}
protected override bool ShouldSkipLine(string line)
{
var result = base.ShouldSkipLine(line);
if (!result)
ParsedLines.Add(line);
return result;
}
}
private class TestModel
{
}
}
}

View File

@ -0,0 +1,9 @@
osu file format v14
[Colours]
// Combo1: 0, 0, 0
//Combo2: 0, 0, 0
// Combo3: 0, 0, 0
Combo1: 100, 100, 100 // Comment at end of line

View File

@ -86,8 +86,8 @@ namespace osu.Game.Tests.Visual.Gameplay
AddStep("move cursor outside", () => InputManager.MoveMouseTo(Player.ScreenSpaceDrawQuad.TopLeft - new Vector2(10)));
pauseAndConfirm();
resumeAndConfirm();
resume();
pause();
confirmClockRunning(true);

View File

@ -58,7 +58,7 @@ namespace osu.Game.Tests.Visual.Menus
bool logoVisible = false;
AddStep("begin loading", () => LoadScreen(loader = new TestLoader()));
AddWaitStep("wait", 2);
AddWaitStep("wait", 3);
AddStep("finish loading", () =>
{
logoVisible = loader.Logo?.Alpha > 0;

View File

@ -11,7 +11,7 @@ using osu.Game.Rulesets;
namespace osu.Game.Tests.Visual.Online
{
[TestFixture]
public class TestCaseDirect : OsuTestCase
public class TestCaseDirectOverlay : OsuTestCase
{
private DirectOverlay direct;
private RulesetStore rulesets;

View File

@ -0,0 +1,40 @@
// 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.Framework.Graphics.Shapes;
using osu.Game.Overlays;
using osuTK.Graphics;
namespace osu.Game.Tests.Visual.Online
{
[TestFixture]
public class TestCaseFullscreenOverlay : OsuTestCase
{
private FullscreenOverlay overlay;
protected override void LoadComplete()
{
base.LoadComplete();
Add(overlay = new TestFullscreenOverlay());
AddStep(@"toggle", overlay.ToggleVisibility);
}
private class TestFullscreenOverlay : FullscreenOverlay
{
public TestFullscreenOverlay()
{
Children = new Drawable[]
{
new Box
{
Colour = Color4.Black,
RelativeSizeAxes = Axes.Both,
},
};
}
}
}
}

View File

@ -11,19 +11,18 @@ using osu.Game.Users;
namespace osu.Game.Tests.Visual.Online
{
[TestFixture]
public class TestCaseSocial : OsuTestCase
public class TestCaseSocialOverlay : OsuTestCase
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(UserPanel),
typeof(SocialPanel),
typeof(FilterControl),
typeof(SocialOverlay),
typeof(SocialGridPanel),
typeof(SocialListPanel)
};
public TestCaseSocial()
public TestCaseSocialOverlay()
{
SocialOverlay s = new SocialOverlay
{

View File

@ -38,7 +38,7 @@ namespace osu.Game.Tests.Visual.Online
header = new ProfileHeader();
Add(header);
AddStep("Show offline dummy", () => header.User.Value = TestCaseUserProfile.TEST_USER);
AddStep("Show offline dummy", () => header.User.Value = TestCaseUserProfileOverlay.TEST_USER);
AddStep("Show null dummy", () => header.User.Value = new User
{

View File

@ -17,7 +17,7 @@ using osu.Game.Users;
namespace osu.Game.Tests.Visual.Online
{
[TestFixture]
public class TestCaseUserProfile : OsuTestCase
public class TestCaseUserProfileOverlay : OsuTestCase
{
private readonly TestUserProfileOverlay profile;
@ -27,7 +27,6 @@ namespace osu.Game.Tests.Visual.Online
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(ProfileHeader),
typeof(UserProfileOverlay),
typeof(RankGraph),
typeof(LineGraph),
typeof(SectionsContainer<>),
@ -72,7 +71,7 @@ namespace osu.Game.Tests.Visual.Online
Achievements = new User.UserAchievement[0],
};
public TestCaseUserProfile()
public TestCaseUserProfileOverlay()
{
Add(profile = new TestUserProfileOverlay());
}

View File

@ -9,17 +9,17 @@ namespace osu.Game.Tests.Visual.Settings
[TestFixture]
public class TestCaseKeyConfiguration : OsuTestCase
{
private readonly KeyBindingOverlay overlay;
private readonly KeyBindingPanel panel;
public TestCaseKeyConfiguration()
{
Child = overlay = new KeyBindingOverlay();
Child = panel = new KeyBindingPanel();
}
protected override void LoadComplete()
{
base.LoadComplete();
overlay.Show();
panel.Show();
}
}
}

View File

@ -11,12 +11,12 @@ namespace osu.Game.Tests.Visual.Settings
[TestFixture]
public class TestCaseSettings : OsuTestCase
{
private readonly SettingsOverlay settings;
private readonly SettingsPanel settings;
private readonly DialogOverlay dialogOverlay;
public TestCaseSettings()
{
settings = new MainSettings
settings = new SettingsOverlay
{
State = Visibility.Visible
};

View File

@ -1,16 +0,0 @@
// 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.Sprites;
namespace osu.Game.Tests.Visual
{
public class TestCaseCharLookup : OsuTestCase
{
public TestCaseCharLookup()
{
AddStep("null", () => { });
AddStep("display acharacter", () => Add(new OsuSpriteText { Text = "振込申請" }));
}
}
}

View File

@ -3,12 +3,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Textures;
using osu.Framework.Platform;
using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Database;
using osu.Game.Graphics;
using osu.Game.Input;
using osu.Game.Input.Bindings;
using osu.Game.IO;
using osu.Game.Online.API;
using osu.Game.Online.Chat;
using osu.Game.Overlays;
using osu.Game.Rulesets;
using osu.Game.Scoring;
using osu.Game.Screens.Menu;
using osu.Game.Skinning;
using osu.Game.Utils;
using osuTK.Graphics;
namespace osu.Game.Tests.Visual
@ -21,6 +39,52 @@ namespace osu.Game.Tests.Visual
typeof(OsuLogo),
};
private IReadOnlyList<Type> requiredGameDependencies => new[]
{
typeof(OsuGame),
typeof(RavenLogger),
typeof(Bindable<RulesetInfo>),
typeof(IBindable<RulesetInfo>),
typeof(OsuLogo),
typeof(IdleTracker),
typeof(OnScreenDisplay),
typeof(NotificationOverlay),
typeof(DirectOverlay),
typeof(SocialOverlay),
typeof(ChannelManager),
typeof(ChatOverlay),
typeof(SettingsOverlay),
typeof(UserProfileOverlay),
typeof(BeatmapSetOverlay),
typeof(LoginOverlay),
typeof(MusicController),
typeof(AccountCreationOverlay),
typeof(DialogOverlay),
};
private IReadOnlyList<Type> requiredGameBaseDependencies => new[]
{
typeof(OsuGameBase),
typeof(DatabaseContextFactory),
typeof(LargeTextureStore),
typeof(OsuConfigManager),
typeof(SkinManager),
typeof(ISkinSource),
typeof(IAPIProvider),
typeof(RulesetStore),
typeof(FileStore),
typeof(ScoreManager),
typeof(BeatmapManager),
typeof(KeyBindingStore),
typeof(SettingsStore),
typeof(RulesetConfigCache),
typeof(OsuColour),
typeof(IBindable<WorkingBeatmap>),
typeof(Bindable<WorkingBeatmap>),
typeof(GlobalActionContainer),
typeof(PreviewTrackManager),
};
[BackgroundDependencyLoader]
private void load(GameHost host)
{
@ -36,6 +100,11 @@ namespace osu.Game.Tests.Visual
},
game
};
AddUntilStep("wait for load", () => game.IsLoaded);
AddAssert("check OsuGame DI members", () => requiredGameDependencies.All(d => game.Dependencies.Get(d) != null));
AddAssert("check OsuGameBase DI members", () => requiredGameBaseDependencies.All(d => Dependencies.Get(d) != null));
}
}
}

View File

@ -9,7 +9,7 @@ using osuTK.Graphics;
namespace osu.Game.Tests.Visual.UserInterface
{
public class TestCaseLoadingAnimation : GridTestCase
public class TestCaseLoadingAnimation : GridTestScene //todo: this should be an OsuTestCase
{
public TestCaseLoadingAnimation()
: base(2, 2)

View File

@ -9,7 +9,6 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Testing;
using osu.Game.Graphics;
using osuTK;
using osuTK.Graphics;
@ -17,7 +16,7 @@ using osuTK.Graphics;
namespace osu.Game.Tests.Visual.UserInterface
{
[TestFixture]
public class TestCaseOsuIcon : TestCase
public class TestCaseOsuIcon : OsuTestCase
{
public TestCaseOsuIcon()
{

View File

@ -54,7 +54,7 @@ namespace osu.Game.Beatmaps.Formats
}
}
protected virtual bool ShouldSkipLine(string line) => string.IsNullOrWhiteSpace(line) || line.StartsWith("//", StringComparison.Ordinal);
protected virtual bool ShouldSkipLine(string line) => string.IsNullOrWhiteSpace(line) || line.AsSpan().TrimStart().StartsWith("//".AsSpan(), StringComparison.Ordinal);
protected virtual void ParseLine(T output, Section section, string line)
{

View File

@ -68,6 +68,48 @@ namespace osu.Game.Graphics
public readonly Color4 GreenDark = FromHex(@"668800");
public readonly Color4 GreenDarker = FromHex(@"445500");
public readonly Color4 Sky = FromHex(@"6bb5ff");
public readonly Color4 GreySkyLighter = FromHex(@"c6e3f4");
public readonly Color4 GreySkyLight = FromHex(@"8ab3cc");
public readonly Color4 GreySky = FromHex(@"405461");
public readonly Color4 GreySkyDark = FromHex(@"303d47");
public readonly Color4 GreySkyDarker = FromHex(@"21272c");
public readonly Color4 Seafoam = FromHex(@"05ffa2");
public readonly Color4 GreySeafoamLighter = FromHex(@"9ebab1");
public readonly Color4 GreySeafoamLight = FromHex(@"4d7365");
public readonly Color4 GreySeafoam = FromHex(@"33413c");
public readonly Color4 GreySeafoamDark = FromHex(@"2c3532");
public readonly Color4 GreySeafoamDarker = FromHex(@"1e2422");
public readonly Color4 Cyan = FromHex(@"05f4fd");
public readonly Color4 GreyCyanLighter = FromHex(@"77b1b3");
public readonly Color4 GreyCyanLight = FromHex(@"436d6f");
public readonly Color4 GreyCyan = FromHex(@"293d3e");
public readonly Color4 GreyCyanDark = FromHex(@"243536");
public readonly Color4 GreyCyanDarker = FromHex(@"1e2929");
public readonly Color4 Lime = FromHex(@"82ff05");
public readonly Color4 GreyLimeLighter = FromHex(@"deff87");
public readonly Color4 GreyLimeLight = FromHex(@"657259");
public readonly Color4 GreyLime = FromHex(@"3f443a");
public readonly Color4 GreyLimeDark = FromHex(@"32352e");
public readonly Color4 GreyLimeDarker = FromHex(@"2e302b");
public readonly Color4 Violet = FromHex(@"bf04ff");
public readonly Color4 GreyVioletLighter = FromHex(@"ebb8fe");
public readonly Color4 GreyVioletLight = FromHex(@"685370");
public readonly Color4 GreyViolet = FromHex(@"46334d");
public readonly Color4 GreyVioletDark = FromHex(@"2c2230");
public readonly Color4 GreyVioletDarker = FromHex(@"201823");
public readonly Color4 Carmine = FromHex(@"ff0542");
public readonly Color4 GreyCarmineLighter = FromHex(@"deaab4");
public readonly Color4 GreyCarmineLight = FromHex(@"644f53");
public readonly Color4 GreyCarmine = FromHex(@"342b2d");
public readonly Color4 GreyCarmineDark = FromHex(@"302a2b");
public readonly Color4 GreyCarmineDarker = FromHex(@"241d1e");
public readonly Color4 Gray0 = FromHex(@"000");
public readonly Color4 Gray1 = FromHex(@"111");
public readonly Color4 Gray2 = FromHex(@"222");

View File

@ -58,16 +58,8 @@ namespace osu.Game
private ChannelManager channelManager;
private MusicController musicController;
private NotificationOverlay notifications;
private LoginOverlay loginOverlay;
private DialogOverlay dialogOverlay;
private AccountCreationOverlay accountCreation;
private DirectOverlay direct;
private SocialOverlay social;
@ -91,7 +83,6 @@ namespace osu.Game
private OsuScreenStack screenStack;
private VolumeOverlay volume;
private OnScreenDisplay onscreenDisplay;
private OsuLogo osuLogo;
private MainMenu menuScreen;
@ -104,10 +95,12 @@ namespace osu.Game
private readonly string[] args;
private SettingsOverlay settings;
private SettingsPanel settings;
private readonly List<OverlayContainer> overlays = new List<OverlayContainer>();
private readonly List<OverlayContainer> toolbarElements = new List<OverlayContainer>();
private readonly List<OverlayContainer> visibleBlockingOverlays = new List<OverlayContainer>();
// todo: move this to SongSelect once Screen has the ability to unsuspend.
@ -124,10 +117,6 @@ namespace osu.Game
RavenLogger = new RavenLogger(this);
}
public void ToggleSettings() => settings.ToggleVisibility();
public void ToggleDirect() => direct.ToggleVisibility();
private void updateBlockingOverlayFade() =>
screenContainer.FadeColour(visibleBlockingOverlays.Any() ? OsuColour.Gray(0.5f) : Color4.White, 500, Easing.OutQuint);
@ -147,12 +136,17 @@ namespace osu.Game
/// <summary>
/// Close all game-wide overlays.
/// </summary>
/// <param name="toolbar">Whether the toolbar should also be hidden.</param>
public void CloseAllOverlays(bool toolbar = true)
/// <param name="hideToolbarElements">Whether the toolbar (and accompanying controls) should also be hidden.</param>
public void CloseAllOverlays(bool hideToolbarElements = true)
{
foreach (var overlay in overlays)
overlay.State = Visibility.Hidden;
if (toolbar) Toolbar.State = Visibility.Hidden;
if (hideToolbarElements)
{
foreach (var overlay in toolbarElements)
overlay.State = Visibility.Hidden;
}
}
private DependencyContainer dependencies;
@ -381,6 +375,8 @@ namespace osu.Game
Container logoContainer;
dependencies.CacheAs(idleTracker = new GameIdleTracker(6000));
AddRange(new Drawable[]
{
new VolumeControlReceptor
@ -402,7 +398,7 @@ namespace osu.Game
rightFloatingOverlayContent = new Container { RelativeSizeAxes = Axes.Both },
leftFloatingOverlayContent = new Container { RelativeSizeAxes = Axes.Both },
topMostOverlayContent = new Container { RelativeSizeAxes = Axes.Both },
idleTracker = new GameIdleTracker(6000)
idleTracker
});
screenStack.ScreenPushed += screenPushed;
@ -426,62 +422,55 @@ namespace osu.Game
CloseAllOverlays(false);
menuScreen?.MakeCurrent();
},
}, topMostOverlayContent.Add);
}, d =>
{
topMostOverlayContent.Add(d);
toolbarElements.Add(d);
});
loadComponentSingleFile(volume = new VolumeOverlay(), leftFloatingOverlayContent.Add);
loadComponentSingleFile(onscreenDisplay = new OnScreenDisplay(), Add);
loadComponentSingleFile(new OnScreenDisplay(), Add, true);
loadComponentSingleFile(notifications = new NotificationOverlay
{
GetToolbarHeight = () => ToolbarOffset,
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
}, rightFloatingOverlayContent.Add);
}, rightFloatingOverlayContent.Add, true);
loadComponentSingleFile(screenshotManager, Add);
//overlay elements
loadComponentSingleFile(direct = new DirectOverlay(), overlayContent.Add);
loadComponentSingleFile(social = new SocialOverlay(), overlayContent.Add);
loadComponentSingleFile(channelManager = new ChannelManager(), AddInternal);
loadComponentSingleFile(chatOverlay = new ChatOverlay(), overlayContent.Add);
loadComponentSingleFile(settings = new MainSettings { GetToolbarHeight = () => ToolbarOffset }, leftFloatingOverlayContent.Add);
loadComponentSingleFile(userProfile = new UserProfileOverlay(), overlayContent.Add);
loadComponentSingleFile(beatmapSetOverlay = new BeatmapSetOverlay(), overlayContent.Add);
loadComponentSingleFile(direct = new DirectOverlay(), overlayContent.Add, true);
loadComponentSingleFile(social = new SocialOverlay(), overlayContent.Add, true);
loadComponentSingleFile(channelManager = new ChannelManager(), AddInternal, true);
loadComponentSingleFile(chatOverlay = new ChatOverlay(), overlayContent.Add, true);
loadComponentSingleFile(settings = new SettingsOverlay { GetToolbarHeight = () => ToolbarOffset }, leftFloatingOverlayContent.Add, true);
loadComponentSingleFile(userProfile = new UserProfileOverlay(), overlayContent.Add, true);
loadComponentSingleFile(beatmapSetOverlay = new BeatmapSetOverlay(), overlayContent.Add, true);
loadComponentSingleFile(loginOverlay = new LoginOverlay
loadComponentSingleFile(new LoginOverlay
{
GetToolbarHeight = () => ToolbarOffset,
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
}, rightFloatingOverlayContent.Add);
}, rightFloatingOverlayContent.Add, true);
loadComponentSingleFile(musicController = new MusicController
loadComponentSingleFile(new MusicController
{
GetToolbarHeight = () => ToolbarOffset,
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
}, rightFloatingOverlayContent.Add);
}, d =>
{
rightFloatingOverlayContent.Add(d);
toolbarElements.Add(d);
}, true);
loadComponentSingleFile(accountCreation = new AccountCreationOverlay(), topMostOverlayContent.Add);
loadComponentSingleFile(dialogOverlay = new DialogOverlay(), topMostOverlayContent.Add);
loadComponentSingleFile(new AccountCreationOverlay(), topMostOverlayContent.Add, true);
loadComponentSingleFile(new DialogOverlay(), topMostOverlayContent.Add, true);
loadComponentSingleFile(externalLinkOpener = new ExternalLinkOpener(), topMostOverlayContent.Add);
dependencies.CacheAs(idleTracker);
dependencies.Cache(settings);
dependencies.Cache(onscreenDisplay);
dependencies.Cache(social);
dependencies.Cache(direct);
dependencies.Cache(chatOverlay);
dependencies.Cache(channelManager);
dependencies.Cache(userProfile);
dependencies.Cache(musicController);
dependencies.Cache(beatmapSetOverlay);
dependencies.Cache(notifications);
dependencies.Cache(loginOverlay);
dependencies.Cache(dialogOverlay);
dependencies.Cache(accountCreation);
chatOverlay.StateChanged += state => channelManager.HighPollRate.Value = state == Visibility.Visible;
Add(externalLinkOpener = new ExternalLinkOpener());
@ -544,7 +533,7 @@ namespace osu.Game
if (notifications.State == Visibility.Visible)
offset -= ToolbarButton.WIDTH / 2;
screenContainer.MoveToX(offset, SettingsOverlay.TRANSITION_LENGTH, Easing.OutQuint);
screenContainer.MoveToX(offset, SettingsPanel.TRANSITION_LENGTH, Easing.OutQuint);
}
settings.StateChanged += _ => updateScreenOffset();
@ -610,9 +599,12 @@ namespace osu.Game
private Task asyncLoadStream;
private void loadComponentSingleFile<T>(T d, Action<T> add)
private void loadComponentSingleFile<T>(T d, Action<T> add, bool cache = false)
where T : Drawable
{
if (cache)
dependencies.Cache(d);
// 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,
// we could avoid the need for scheduling altogether.

View File

@ -220,8 +220,10 @@ namespace osu.Game
// TODO: This is temporary until we reimplement the local FPS display.
// It's just to allow end-users to access the framework FPS display without knowing the shortcut key.
fpsDisplayVisible = LocalConfig.GetBindable<bool>(OsuSetting.ShowFpsDisplay);
fpsDisplayVisible.ValueChanged += visible => { FrameStatisticsMode = visible.NewValue ? FrameStatisticsMode.Minimal : FrameStatisticsMode.None; };
fpsDisplayVisible.ValueChanged += visible => { FrameStatistics.Value = visible.NewValue ? FrameStatisticsMode.Minimal : FrameStatisticsMode.None; };
fpsDisplayVisible.TriggerChange();
FrameStatistics.ValueChanged += e => fpsDisplayVisible.Value = e.NewValue != FrameStatisticsMode.None;
}
private void runMigrations()

View File

@ -4,26 +4,22 @@
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Overlays.BeatmapSet;
using osu.Game.Overlays.BeatmapSet.Scores;
using osu.Game.Rulesets;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Overlays
{
public class BeatmapSetOverlay : WaveOverlayContainer
public class BeatmapSetOverlay : FullscreenOverlay
{
private const int fade_duration = 300;
@ -32,7 +28,6 @@ namespace osu.Game.Overlays
private readonly Header header;
private IAPIProvider api;
private RulesetStore rulesets;
private readonly ScrollContainer scroll;
@ -46,24 +41,6 @@ namespace osu.Game.Overlays
{
Info info;
ScoresContainer scores;
Waves.FirstWaveColour = OsuColour.Gray(0.4f);
Waves.SecondWaveColour = OsuColour.Gray(0.3f);
Waves.ThirdWaveColour = OsuColour.Gray(0.2f);
Waves.FourthWaveColour = OsuColour.Gray(0.1f);
Anchor = Anchor.TopCentre;
Origin = Anchor.TopCentre;
RelativeSizeAxes = Axes.Both;
Width = 0.85f;
Masking = true;
EdgeEffect = new EdgeEffectParameters
{
Colour = Color4.Black.Opacity(0),
Type = EdgeEffectType.Shadow,
Radius = 3,
Offset = new Vector2(0f, 1f),
};
Children = new Drawable[]
{
@ -102,22 +79,15 @@ namespace osu.Game.Overlays
}
[BackgroundDependencyLoader]
private void load(IAPIProvider api, RulesetStore rulesets)
private void load(RulesetStore rulesets)
{
this.api = api;
this.rulesets = rulesets;
}
protected override void PopIn()
protected override void PopOutComplete()
{
base.PopIn();
FadeEdgeEffectTo(0.25f, WaveContainer.APPEAR_DURATION, Easing.In);
}
protected override void PopOut()
{
base.PopOut();
FadeEdgeEffectTo(0, WaveContainer.DISAPPEAR_DURATION, Easing.Out).OnComplete(_ => beatmapSet.Value = null);
base.PopOutComplete();
beatmapSet.Value = null;
}
protected override bool OnClick(ClickEvent e)
@ -135,7 +105,7 @@ namespace osu.Game.Overlays
beatmapSet.Value = res.ToBeatmapSet(rulesets);
header.Picker.Beatmap.Value = header.BeatmapSet.Value.Beatmaps.First(b => b.OnlineBeatmapID == beatmapId);
};
api.Queue(req);
API.Queue(req);
Show();
}
@ -144,7 +114,7 @@ namespace osu.Game.Overlays
beatmapSet.Value = null;
var req = new GetBeatmapSetRequest(beatmapSetId);
req.Success += res => beatmapSet.Value = res.ToBeatmapSet(rulesets);
api.Queue(req);
API.Queue(req);
Show();
}

View File

@ -14,7 +14,6 @@ using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Overlays.Direct;
using osu.Game.Overlays.SearchableList;
@ -28,7 +27,6 @@ namespace osu.Game.Overlays
{
private const float panel_padding = 10f;
private IAPIProvider api;
private RulesetStore rulesets;
private readonly FillFlowContainer resultCountsContainer;
@ -87,8 +85,6 @@ namespace osu.Game.Overlays
public DirectOverlay()
{
RelativeSizeAxes = Axes.Both;
// osu!direct colours are not part of the standard palette
Waves.FirstWaveColour = OsuColour.FromHex(@"19b0e2");
@ -165,9 +161,8 @@ namespace osu.Game.Overlays
}
[BackgroundDependencyLoader]
private void load(OsuColour colours, IAPIProvider api, RulesetStore rulesets, PreviewTrackManager previewTrackManager)
private void load(OsuColour colours, RulesetStore rulesets, PreviewTrackManager previewTrackManager)
{
this.api = api;
this.rulesets = rulesets;
this.previewTrackManager = previewTrackManager;
@ -260,7 +255,7 @@ namespace osu.Game.Overlays
if (State == Visibility.Hidden)
return;
if (api == null)
if (API == null)
return;
previewTrackManager.StopAnyPlaying(this);
@ -286,7 +281,7 @@ namespace osu.Game.Overlays
});
};
api.Queue(getSetsRequest);
API.Queue(getSetsRequest);
}
private int distinctCount(List<string> list) => list.Distinct().ToArray().Length;

View File

@ -0,0 +1,75 @@
// 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.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Effects;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Online.API;
using osuTK.Graphics;
namespace osu.Game.Overlays
{
public abstract class FullscreenOverlay : WaveOverlayContainer, IOnlineComponent
{
[Resolved]
protected IAPIProvider API { get; private set; }
protected FullscreenOverlay()
{
Waves.FirstWaveColour = OsuColour.Gray(0.4f);
Waves.SecondWaveColour = OsuColour.Gray(0.3f);
Waves.ThirdWaveColour = OsuColour.Gray(0.2f);
Waves.FourthWaveColour = OsuColour.Gray(0.1f);
RelativeSizeAxes = Axes.Both;
RelativePositionAxes = Axes.Both;
Width = 0.85f;
Anchor = Anchor.TopCentre;
Origin = Anchor.TopCentre;
Masking = true;
EdgeEffect = new EdgeEffectParameters
{
Colour = Color4.Black.Opacity(0),
Type = EdgeEffectType.Shadow,
Radius = 10
};
}
protected override void PopIn()
{
base.PopIn();
FadeEdgeEffectTo(0.4f, WaveContainer.APPEAR_DURATION, Easing.Out);
}
protected override void PopOut()
{
base.PopOut();
FadeEdgeEffectTo(0, WaveContainer.DISAPPEAR_DURATION, Easing.In).OnComplete(_ => PopOutComplete());
}
protected virtual void PopOutComplete()
{
}
protected override void LoadComplete()
{
base.LoadComplete();
API.Register(this);
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
API?.Unregister(this);
}
public virtual void APIStateChanged(IAPIProvider api, APIState state)
{
}
}
}

View File

@ -28,7 +28,7 @@ namespace osu.Game.Overlays.KeyBinding
this.variant = variant;
FlowContent.Spacing = new Vector2(0, 1);
FlowContent.Padding = new MarginPadding { Left = SettingsOverlay.CONTENT_MARGINS, Right = SettingsOverlay.CONTENT_MARGINS };
FlowContent.Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS, Right = SettingsPanel.CONTENT_MARGINS };
}
[BackgroundDependencyLoader]

View File

@ -18,7 +18,7 @@ using osuTK;
namespace osu.Game.Overlays
{
public class KeyBindingOverlay : SettingsOverlay
public class KeyBindingPanel : SettingsPanel
{
protected override Drawable CreateHeader() => new SettingsHeader("key configuration", "Customise your keys!");
@ -38,7 +38,7 @@ namespace osu.Game.Overlays
});
}
public KeyBindingOverlay()
public KeyBindingPanel()
: base(true)
{
}

View File

@ -1,77 +0,0 @@
// 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.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Overlays.Settings;
using osu.Game.Overlays.Settings.Sections;
using osuTK.Graphics;
using System.Collections.Generic;
namespace osu.Game.Overlays
{
public class MainSettings : SettingsOverlay
{
private readonly KeyBindingOverlay keyBindingOverlay;
protected override IEnumerable<SettingsSection> CreateSections() => new SettingsSection[]
{
new GeneralSection(),
new GraphicsSection(),
new GameplaySection(),
new AudioSection(),
new SkinSection(),
new InputSection(keyBindingOverlay),
new OnlineSection(),
new MaintenanceSection(),
new DebugSection(),
};
protected override Drawable CreateHeader() => new SettingsHeader("settings", "Change the way osu! behaves");
protected override Drawable CreateFooter() => new SettingsFooter();
public MainSettings()
: base(true)
{
keyBindingOverlay = new KeyBindingOverlay
{
Depth = 1,
Anchor = Anchor.TopRight,
};
keyBindingOverlay.StateChanged += keyBindingOverlay_StateChanged;
}
public override bool AcceptsFocus => keyBindingOverlay.State != Visibility.Visible;
private void keyBindingOverlay_StateChanged(Visibility visibility)
{
switch (visibility)
{
case Visibility.Visible:
Background.FadeTo(0.9f, 300, Easing.OutQuint);
Sidebar?.FadeColour(Color4.DarkGray, 300, Easing.OutQuint);
SectionsContainer.FadeOut(300, Easing.OutQuint);
ContentContainer.MoveToX(-WIDTH, 500, Easing.OutQuint);
break;
case Visibility.Hidden:
Background.FadeTo(0.6f, 500, Easing.OutQuint);
Sidebar?.FadeColour(Color4.White, 300, Easing.OutQuint);
SectionsContainer.FadeIn(500, Easing.OutQuint);
ContentContainer.MoveToX(0, 500, Easing.OutQuint);
break;
}
}
protected override float ExpandedPosition => keyBindingOverlay.State == Visibility.Visible ? -WIDTH : base.ExpandedPosition;
[BackgroundDependencyLoader]
private void load()
{
ContentContainer.Add(keyBindingOverlay);
}
}
}

View File

@ -87,14 +87,6 @@ namespace osu.Game.Overlays.Profile.Header
addSpacer(topLinkContainer);
if (user.PlayStyles?.Length > 0)
{
topLinkContainer.AddText("Plays with ");
topLinkContainer.AddText(string.Join(", ", user.PlayStyles.Select(style => style.GetDescription())), embolden);
addSpacer(topLinkContainer);
}
if (user.LastVisit.HasValue)
{
topLinkContainer.AddText("Last seen ");
@ -103,6 +95,14 @@ namespace osu.Game.Overlays.Profile.Header
addSpacer(topLinkContainer);
}
if (user.PlayStyles?.Length > 0)
{
topLinkContainer.AddText("Plays with ");
topLinkContainer.AddText(string.Join(", ", user.PlayStyles.Select(style => style.GetDescription())), embolden);
addSpacer(topLinkContainer);
}
topLinkContainer.AddText("Contributed ");
topLinkContainer.AddLink($@"{user.PostCount:#,##0} forum posts", $"https://osu.ppy.sh/users/{user.Id}/posts", creationParameters: embolden);

View File

@ -11,7 +11,7 @@ using osu.Game.Graphics.Containers;
namespace osu.Game.Overlays.SearchableList
{
public abstract class SearchableListOverlay : WaveOverlayContainer
public abstract class SearchableListOverlay : FullscreenOverlay
{
public static readonly float WIDTH_PADDING = 80;
}
@ -32,8 +32,6 @@ namespace osu.Game.Overlays.SearchableList
protected SearchableListOverlay()
{
RelativeSizeAxes = Axes.Both;
Children = new Drawable[]
{
new Box

View File

@ -9,7 +9,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
{
protected override string Header => "Keyboard";
public KeyboardSettings(KeyBindingOverlay keyConfig)
public KeyboardSettings(KeyBindingPanel keyConfig)
{
Children = new Drawable[]
{

View File

@ -12,7 +12,7 @@ namespace osu.Game.Overlays.Settings.Sections
public override string Header => "Input";
public override IconUsage Icon => FontAwesome.Regular.Keyboard;
public InputSection(KeyBindingOverlay keyConfig)
public InputSection(KeyBindingPanel keyConfig)
{
Children = new Drawable[]
{

View File

@ -14,7 +14,7 @@ namespace osu.Game.Overlays.Settings
public SettingsButton()
{
RelativeSizeAxes = Axes.X;
Padding = new MarginPadding { Left = SettingsOverlay.CONTENT_MARGINS, Right = SettingsOverlay.CONTENT_MARGINS };
Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS, Right = SettingsPanel.CONTENT_MARGINS };
}
public string TooltipText { get; set; }

View File

@ -41,7 +41,7 @@ namespace osu.Game.Overlays.Settings
Font = OsuFont.GetFont(size: 40),
Margin = new MarginPadding
{
Left = SettingsOverlay.CONTENT_MARGINS,
Left = SettingsPanel.CONTENT_MARGINS,
Top = Toolbar.Toolbar.TOOLTIP_HEIGHT
},
},
@ -52,7 +52,7 @@ namespace osu.Game.Overlays.Settings
Font = OsuFont.GetFont(size: 18),
Margin = new MarginPadding
{
Left = SettingsOverlay.CONTENT_MARGINS,
Left = SettingsPanel.CONTENT_MARGINS,
Bottom = 30
},
},

View File

@ -87,7 +87,7 @@ namespace osu.Game.Overlays.Settings
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
Padding = new MarginPadding { Right = SettingsOverlay.CONTENT_MARGINS };
Padding = new MarginPadding { Right = SettingsPanel.CONTENT_MARGINS };
InternalChildren = new Drawable[]
{
@ -96,7 +96,7 @@ namespace osu.Game.Overlays.Settings
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Padding = new MarginPadding { Left = SettingsOverlay.CONTENT_MARGINS },
Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS },
Child = Control = CreateControl()
},
};
@ -131,7 +131,7 @@ namespace osu.Game.Overlays.Settings
public RestoreDefaultValueButton()
{
RelativeSizeAxes = Axes.Y;
Width = SettingsOverlay.CONTENT_MARGINS;
Width = SettingsPanel.CONTENT_MARGINS;
Alpha = 0f;
}

View File

@ -83,7 +83,7 @@ namespace osu.Game.Overlays.Settings
Font = OsuFont.GetFont(size: header_size),
Text = Header,
Colour = colours.Yellow,
Margin = new MarginPadding { Left = SettingsOverlay.CONTENT_MARGINS, Right = SettingsOverlay.CONTENT_MARGINS }
Margin = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS, Right = SettingsPanel.CONTENT_MARGINS }
},
FlowContent
}

View File

@ -53,7 +53,7 @@ namespace osu.Game.Overlays.Settings
new OsuSpriteText
{
Text = Header.ToUpperInvariant(),
Margin = new MarginPadding { Bottom = 10, Left = SettingsOverlay.CONTENT_MARGINS, Right = SettingsOverlay.CONTENT_MARGINS },
Margin = new MarginPadding { Bottom = 10, Left = SettingsPanel.CONTENT_MARGINS, Right = SettingsPanel.CONTENT_MARGINS },
Font = OsuFont.GetFont(weight: FontWeight.Black),
},
FlowContent

View File

@ -1,224 +1,77 @@
// 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.Collections.Generic;
using System.Linq;
using osuTK;
using osuTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays.Settings;
using osu.Game.Overlays.Settings.Sections;
using osuTK.Graphics;
using System.Collections.Generic;
namespace osu.Game.Overlays
{
public abstract class SettingsOverlay : OsuFocusedOverlayContainer
public class SettingsOverlay : SettingsPanel
{
public const float CONTENT_MARGINS = 15;
private readonly KeyBindingPanel keyBindingPanel;
public const float TRANSITION_LENGTH = 600;
private const float sidebar_width = Sidebar.DEFAULT_WIDTH;
protected const float WIDTH = 400;
private const float sidebar_padding = 10;
protected Container<Drawable> ContentContainer;
protected override Container<Drawable> Content => ContentContainer;
protected Sidebar Sidebar;
private SidebarButton selectedSidebarButton;
protected SettingsSectionsContainer SectionsContainer;
private SearchTextBox searchTextBox;
/// <summary>
/// Provide a source for the toolbar height.
/// </summary>
public Func<float> GetToolbarHeight;
private readonly bool showSidebar;
protected Box Background;
protected SettingsOverlay(bool showSidebar)
protected override IEnumerable<SettingsSection> CreateSections() => new SettingsSection[]
{
this.showSidebar = showSidebar;
RelativeSizeAxes = Axes.Y;
AutoSizeAxes = Axes.X;
new GeneralSection(),
new GraphicsSection(),
new GameplaySection(),
new AudioSection(),
new SkinSection(),
new InputSection(keyBindingPanel),
new OnlineSection(),
new MaintenanceSection(),
new DebugSection(),
};
protected override Drawable CreateHeader() => new SettingsHeader("settings", "Change the way osu! behaves");
protected override Drawable CreateFooter() => new SettingsFooter();
public SettingsOverlay()
: base(true)
{
keyBindingPanel = new KeyBindingPanel
{
Depth = 1,
Anchor = Anchor.TopRight,
};
keyBindingPanel.StateChanged += keyBindingPanelStateChanged;
}
protected virtual IEnumerable<SettingsSection> CreateSections() => null;
public override bool AcceptsFocus => keyBindingPanel.State != Visibility.Visible;
private void keyBindingPanelStateChanged(Visibility visibility)
{
switch (visibility)
{
case Visibility.Visible:
Background.FadeTo(0.9f, 300, Easing.OutQuint);
Sidebar?.FadeColour(Color4.DarkGray, 300, Easing.OutQuint);
SectionsContainer.FadeOut(300, Easing.OutQuint);
ContentContainer.MoveToX(-WIDTH, 500, Easing.OutQuint);
break;
case Visibility.Hidden:
Background.FadeTo(0.6f, 500, Easing.OutQuint);
Sidebar?.FadeColour(Color4.White, 300, Easing.OutQuint);
SectionsContainer.FadeIn(500, Easing.OutQuint);
ContentContainer.MoveToX(0, 500, Easing.OutQuint);
break;
}
}
protected override float ExpandedPosition => keyBindingPanel.State == Visibility.Visible ? -WIDTH : base.ExpandedPosition;
[BackgroundDependencyLoader]
private void load()
{
InternalChild = ContentContainer = new Container
{
Width = WIDTH,
RelativeSizeAxes = Axes.Y,
Children = new Drawable[]
{
Background = new Box
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Scale = new Vector2(2, 1), // over-extend to the left for transitions
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black,
Alpha = 0.6f,
},
SectionsContainer = new SettingsSectionsContainer
{
Masking = true,
RelativeSizeAxes = Axes.Both,
ExpandableHeader = CreateHeader(),
FixedHeader = searchTextBox = new SearchTextBox
{
RelativeSizeAxes = Axes.X,
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
Width = 0.95f,
Margin = new MarginPadding
{
Top = 20,
Bottom = 20
},
Exit = Hide,
},
Footer = CreateFooter()
},
}
};
if (showSidebar)
{
AddInternal(Sidebar = new Sidebar { Width = sidebar_width });
SectionsContainer.SelectedSection.ValueChanged += section =>
{
selectedSidebarButton.Selected = false;
selectedSidebarButton = Sidebar.Children.Single(b => b.Section == section.NewValue);
selectedSidebarButton.Selected = true;
};
}
searchTextBox.Current.ValueChanged += term => SectionsContainer.SearchContainer.SearchTerm = term.NewValue;
CreateSections()?.ForEach(AddSection);
}
protected void AddSection(SettingsSection section)
{
SectionsContainer.Add(section);
if (Sidebar != null)
{
var button = new SidebarButton
{
Section = section,
Action = s =>
{
SectionsContainer.ScrollTo(s);
Sidebar.State = ExpandedState.Contracted;
},
};
Sidebar.Add(button);
if (selectedSidebarButton == null)
{
selectedSidebarButton = Sidebar.Children.First();
selectedSidebarButton.Selected = true;
}
}
}
protected virtual Drawable CreateHeader() => new Container();
protected virtual Drawable CreateFooter() => new Container();
protected override void PopIn()
{
base.PopIn();
ContentContainer.MoveToX(ExpandedPosition, TRANSITION_LENGTH, Easing.OutQuint);
Sidebar?.MoveToX(0, TRANSITION_LENGTH, Easing.OutQuint);
this.FadeTo(1, TRANSITION_LENGTH, Easing.OutQuint);
searchTextBox.HoldFocus = true;
}
protected virtual float ExpandedPosition => 0;
protected override void PopOut()
{
base.PopOut();
ContentContainer.MoveToX(-WIDTH, TRANSITION_LENGTH, Easing.OutQuint);
Sidebar?.MoveToX(-sidebar_width, TRANSITION_LENGTH, Easing.OutQuint);
this.FadeTo(0, TRANSITION_LENGTH, Easing.OutQuint);
searchTextBox.HoldFocus = false;
if (searchTextBox.HasFocus)
GetContainingInputManager().ChangeFocus(null);
}
public override bool AcceptsFocus => true;
protected override void OnFocus(FocusEvent e)
{
searchTextBox.TakeFocus();
base.OnFocus(e);
}
protected override void UpdateAfterChildren()
{
base.UpdateAfterChildren();
ContentContainer.Margin = new MarginPadding { Left = Sidebar?.DrawWidth ?? 0 };
ContentContainer.Padding = new MarginPadding { Top = GetToolbarHeight?.Invoke() ?? 0 };
}
protected class SettingsSectionsContainer : SectionsContainer<SettingsSection>
{
public SearchContainer<SettingsSection> SearchContainer;
protected override FlowContainer<SettingsSection> CreateScrollContentContainer()
=> SearchContainer = new SearchContainer<SettingsSection>
{
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
Direction = FillDirection.Vertical,
};
public SettingsSectionsContainer()
{
HeaderBackground = new Box
{
Colour = Color4.Black,
RelativeSizeAxes = Axes.Both
};
}
protected override void UpdateAfterChildren()
{
base.UpdateAfterChildren();
// no null check because the usage of this class is strict
HeaderBackground.Alpha = -ExpandableHeader.Y / ExpandableHeader.LayoutSize.Y * 0.5f;
}
ContentContainer.Add(keyBindingPanel);
}
}
}

View File

@ -0,0 +1,224 @@
// 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.Collections.Generic;
using System.Linq;
using osuTK;
using osuTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays.Settings;
namespace osu.Game.Overlays
{
public abstract class SettingsPanel : OsuFocusedOverlayContainer
{
public const float CONTENT_MARGINS = 15;
public const float TRANSITION_LENGTH = 600;
private const float sidebar_width = Sidebar.DEFAULT_WIDTH;
protected const float WIDTH = 400;
private const float sidebar_padding = 10;
protected Container<Drawable> ContentContainer;
protected override Container<Drawable> Content => ContentContainer;
protected Sidebar Sidebar;
private SidebarButton selectedSidebarButton;
protected SettingsSectionsContainer SectionsContainer;
private SearchTextBox searchTextBox;
/// <summary>
/// Provide a source for the toolbar height.
/// </summary>
public Func<float> GetToolbarHeight;
private readonly bool showSidebar;
protected Box Background;
protected SettingsPanel(bool showSidebar)
{
this.showSidebar = showSidebar;
RelativeSizeAxes = Axes.Y;
AutoSizeAxes = Axes.X;
}
protected virtual IEnumerable<SettingsSection> CreateSections() => null;
[BackgroundDependencyLoader]
private void load()
{
InternalChild = ContentContainer = new Container
{
Width = WIDTH,
RelativeSizeAxes = Axes.Y,
Children = new Drawable[]
{
Background = new Box
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Scale = new Vector2(2, 1), // over-extend to the left for transitions
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black,
Alpha = 0.6f,
},
SectionsContainer = new SettingsSectionsContainer
{
Masking = true,
RelativeSizeAxes = Axes.Both,
ExpandableHeader = CreateHeader(),
FixedHeader = searchTextBox = new SearchTextBox
{
RelativeSizeAxes = Axes.X,
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
Width = 0.95f,
Margin = new MarginPadding
{
Top = 20,
Bottom = 20
},
Exit = Hide,
},
Footer = CreateFooter()
},
}
};
if (showSidebar)
{
AddInternal(Sidebar = new Sidebar { Width = sidebar_width });
SectionsContainer.SelectedSection.ValueChanged += section =>
{
selectedSidebarButton.Selected = false;
selectedSidebarButton = Sidebar.Children.Single(b => b.Section == section.NewValue);
selectedSidebarButton.Selected = true;
};
}
searchTextBox.Current.ValueChanged += term => SectionsContainer.SearchContainer.SearchTerm = term.NewValue;
CreateSections()?.ForEach(AddSection);
}
protected void AddSection(SettingsSection section)
{
SectionsContainer.Add(section);
if (Sidebar != null)
{
var button = new SidebarButton
{
Section = section,
Action = s =>
{
SectionsContainer.ScrollTo(s);
Sidebar.State = ExpandedState.Contracted;
},
};
Sidebar.Add(button);
if (selectedSidebarButton == null)
{
selectedSidebarButton = Sidebar.Children.First();
selectedSidebarButton.Selected = true;
}
}
}
protected virtual Drawable CreateHeader() => new Container();
protected virtual Drawable CreateFooter() => new Container();
protected override void PopIn()
{
base.PopIn();
ContentContainer.MoveToX(ExpandedPosition, TRANSITION_LENGTH, Easing.OutQuint);
Sidebar?.MoveToX(0, TRANSITION_LENGTH, Easing.OutQuint);
this.FadeTo(1, TRANSITION_LENGTH, Easing.OutQuint);
searchTextBox.HoldFocus = true;
}
protected virtual float ExpandedPosition => 0;
protected override void PopOut()
{
base.PopOut();
ContentContainer.MoveToX(-WIDTH, TRANSITION_LENGTH, Easing.OutQuint);
Sidebar?.MoveToX(-sidebar_width, TRANSITION_LENGTH, Easing.OutQuint);
this.FadeTo(0, TRANSITION_LENGTH, Easing.OutQuint);
searchTextBox.HoldFocus = false;
if (searchTextBox.HasFocus)
GetContainingInputManager().ChangeFocus(null);
}
public override bool AcceptsFocus => true;
protected override void OnFocus(FocusEvent e)
{
searchTextBox.TakeFocus();
base.OnFocus(e);
}
protected override void UpdateAfterChildren()
{
base.UpdateAfterChildren();
ContentContainer.Margin = new MarginPadding { Left = Sidebar?.DrawWidth ?? 0 };
ContentContainer.Padding = new MarginPadding { Top = GetToolbarHeight?.Invoke() ?? 0 };
}
protected class SettingsSectionsContainer : SectionsContainer<SettingsSection>
{
public SearchContainer<SettingsSection> SearchContainer;
protected override FlowContainer<SettingsSection> CreateScrollContentContainer()
=> SearchContainer = new SearchContainer<SettingsSection>
{
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
Direction = FillDirection.Vertical,
};
public SettingsSectionsContainer()
{
HeaderBackground = new Box
{
Colour = Color4.Black,
RelativeSizeAxes = Axes.Both
};
}
protected override void UpdateAfterChildren()
{
base.UpdateAfterChildren();
// no null check because the usage of this class is strict
HeaderBackground.Alpha = -ExpandableHeader.Y / ExpandableHeader.LayoutSize.Y * 0.5f;
}
}
}
}

View File

@ -3,7 +3,6 @@
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osuTK;
using osuTK.Graphics;
@ -20,9 +19,8 @@ using osu.Framework.Threading;
namespace osu.Game.Overlays
{
public class SocialOverlay : SearchableListOverlay<SocialTab, SocialSortCriteria, SortDirection>, IOnlineComponent
public class SocialOverlay : SearchableListOverlay<SocialTab, SocialSortCriteria, SortDirection>
{
private IAPIProvider api;
private readonly LoadingAnimation loading;
private FillFlowContainer<SocialPanel> panels;
@ -88,13 +86,6 @@ namespace osu.Game.Overlays
currentQuery.BindTo(Filter.Search.Current);
}
[BackgroundDependencyLoader]
private void load(IAPIProvider api)
{
this.api = api;
api.Register(this);
}
private void recreatePanels(PanelDisplayStyle displayStyle)
{
clearPanels();
@ -160,7 +151,7 @@ namespace osu.Game.Overlays
loading.Hide();
getUsersRequest?.Cancel();
if (api?.IsLoggedIn != true)
if (API?.IsLoggedIn != true)
return;
switch (Header.Tabs.Current.Value)
@ -168,13 +159,13 @@ namespace osu.Game.Overlays
case SocialTab.Friends:
var friendRequest = new GetFriendsRequest(); // TODO filter arguments?
friendRequest.Success += updateUsers;
api.Queue(getUsersRequest = friendRequest);
API.Queue(getUsersRequest = friendRequest);
break;
default:
var userRequest = new GetUsersRequest(); // TODO filter arguments!
userRequest.Success += response => updateUsers(response.Select(r => r.User));
api.Queue(getUsersRequest = userRequest);
API.Queue(getUsersRequest = userRequest);
break;
}
@ -197,7 +188,7 @@ namespace osu.Game.Overlays
}
}
public void APIStateChanged(IAPIProvider api, APIState state)
public override void APIStateChanged(IAPIProvider api, APIState state)
{
switch (state)
{

View File

@ -16,7 +16,7 @@ namespace osu.Game.Overlays.Toolbar
}
[BackgroundDependencyLoader(true)]
private void load(MainSettings settings)
private void load(SettingsOverlay settings)
{
StateContainer = settings;
}

View File

@ -3,76 +3,31 @@
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Overlays.Profile;
using osu.Game.Overlays.Profile.Sections;
using osu.Game.Users;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Overlays
{
public class UserProfileOverlay : WaveOverlayContainer
public class UserProfileOverlay : FullscreenOverlay
{
private ProfileSection lastSection;
private ProfileSection[] sections;
private GetUserRequest userReq;
private IAPIProvider api;
protected ProfileHeader Header;
private SectionsContainer<ProfileSection> sectionsContainer;
private ProfileTabControl tabs;
public const float CONTENT_X_MARGIN = 70;
public UserProfileOverlay()
{
Waves.FirstWaveColour = OsuColour.Gray(0.4f);
Waves.SecondWaveColour = OsuColour.Gray(0.3f);
Waves.ThirdWaveColour = OsuColour.Gray(0.2f);
Waves.FourthWaveColour = OsuColour.Gray(0.1f);
RelativeSizeAxes = Axes.Both;
RelativePositionAxes = Axes.Both;
Width = 0.85f;
Anchor = Anchor.TopCentre;
Origin = Anchor.TopCentre;
Masking = true;
EdgeEffect = new EdgeEffectParameters
{
Colour = Color4.Black.Opacity(0),
Type = EdgeEffectType.Shadow,
Radius = 10
};
}
[BackgroundDependencyLoader]
private void load(IAPIProvider api)
{
this.api = api;
}
protected override void PopIn()
{
base.PopIn();
FadeEdgeEffectTo(0.5f, WaveContainer.APPEAR_DURATION, Easing.In);
}
protected override void PopOut()
{
base.PopOut();
FadeEdgeEffectTo(0, WaveContainer.DISAPPEAR_DURATION, Easing.Out);
}
public void ShowUser(long userId) => ShowUser(new User { Id = userId });
public void ShowUser(User user, bool fetchOnline = true)
@ -154,7 +109,7 @@ namespace osu.Game.Overlays
{
userReq = new GetUserRequest(user.Id);
userReq.Success += userLoadComplete;
api.Queue(userReq);
API.Queue(userReq);
}
else
{

View File

@ -4,21 +4,20 @@
using System;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Events;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Overlays.Volume
{
public class MuteButton : Container, IHasCurrentValue<bool>
public class MuteButton : OsuButton, IHasCurrentValue<bool>
{
private readonly Bindable<bool> current = new Bindable<bool>();
@ -36,63 +35,57 @@ namespace osu.Game.Overlays.Volume
}
private Color4 hoveredColour, unhoveredColour;
private const float width = 100;
public const float HEIGHT = 35;
public MuteButton()
{
Masking = true;
BorderThickness = 3;
CornerRadius = HEIGHT / 2;
Content.BorderThickness = 3;
Content.CornerRadius = HEIGHT / 2;
Size = new Vector2(width, HEIGHT);
Action = () => Current.Value = !Current.Value;
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
hoveredColour = colours.YellowDark;
BorderColour = unhoveredColour = colours.Gray1.Opacity(0.9f);
Content.BorderColour = unhoveredColour = colours.Gray1;
BackgroundColour = colours.Gray1;
SpriteIcon icon;
AddRange(new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = colours.Gray1,
Alpha = 0.9f,
},
icon = new SpriteIcon
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(20),
}
});
Current.ValueChanged += muted =>
{
icon.Icon = muted.NewValue ? FontAwesome.Solid.VolumeOff : FontAwesome.Solid.VolumeUp;
icon.Margin = new MarginPadding { Left = muted.NewValue ? width / 2 - 15 : width / 2 - 10 }; //Magic numbers to line up both icons because they're different widths
icon.Icon = muted.NewValue ? FontAwesome.Solid.VolumeMute : FontAwesome.Solid.VolumeUp;
};
Current.TriggerChange();
}
protected override bool OnHover(HoverEvent e)
{
this.TransformTo<MuteButton, SRGBColour>("BorderColour", hoveredColour, 500, Easing.OutQuint);
Content.TransformTo<Container<Drawable>, SRGBColour>("BorderColour", hoveredColour, 500, Easing.OutQuint);
return false;
}
protected override void OnHoverLost(HoverLostEvent e)
{
this.TransformTo<MuteButton, SRGBColour>("BorderColour", unhoveredColour, 500, Easing.OutQuint);
}
protected override bool OnClick(ClickEvent e)
{
Current.Value = !Current.Value;
return true;
Content.TransformTo<Container<Drawable>, SRGBColour>("BorderColour", unhoveredColour, 500, Easing.OutQuint);
}
}
}

View File

@ -20,6 +20,7 @@ using osu.Game.Screens.Multi;
using osu.Game.Screens.Select;
using osu.Game.Screens.Tournament;
using osu.Framework.Platform;
using osu.Game.Overlays;
namespace osu.Game.Screens.Menu
{
@ -45,7 +46,7 @@ namespace osu.Game.Screens.Menu
protected override BackgroundScreen CreateBackground() => background;
[BackgroundDependencyLoader(true)]
private void load(OsuGame game = null)
private void load(DirectOverlay direct, SettingsOverlay settings)
{
if (host.CanExit)
AddInternal(new ExitConfirmOverlay { Action = this.Exit });
@ -86,11 +87,8 @@ namespace osu.Game.Screens.Menu
}
};
if (game != null)
{
buttons.OnSettings = game.ToggleSettings;
buttons.OnDirect = game.ToggleDirect;
}
buttons.OnSettings = () => settings?.ToggleVisibility();
buttons.OnDirect = () => direct?.ToggleVisibility();
LoadComponentAsync(background = new BackgroundScreenDefault());
preloadSongSelect();

View File

@ -1,6 +1,7 @@
// 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 osuTK;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
@ -66,13 +67,11 @@ namespace osu.Game.Storyboards.Drawables
[BackgroundDependencyLoader]
private void load(IBindable<WorkingBeatmap> beatmap, TextureStore textureStore)
{
var basePath = Animation.Path.ToLowerInvariant();
for (var frame = 0; frame < Animation.FrameCount; frame++)
{
var framePath = basePath.Replace(".", frame + ".");
var framePath = Animation.Path.Replace(".", frame + ".");
var path = beatmap.Value.BeatmapSetInfo.Files.Find(f => f.Filename.ToLowerInvariant() == framePath)?.FileInfo.StoragePath;
var path = beatmap.Value.BeatmapSetInfo.Files.Find(f => f.Filename.Equals(framePath, StringComparison.InvariantCultureIgnoreCase))?.FileInfo.StoragePath;
if (path == null)
continue;

View File

@ -1,6 +1,7 @@
// 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 osuTK;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
@ -65,8 +66,7 @@ namespace osu.Game.Storyboards.Drawables
[BackgroundDependencyLoader]
private void load(IBindable<WorkingBeatmap> beatmap, TextureStore textureStore)
{
var spritePath = Sprite.Path.ToLowerInvariant();
var path = beatmap.Value.BeatmapSetInfo.Files.Find(f => f.Filename.ToLowerInvariant() == spritePath)?.FileInfo.StoragePath;
var path = beatmap.Value.BeatmapSetInfo.Files.Find(f => f.Filename.Equals(Sprite.Path, StringComparison.InvariantCultureIgnoreCase))?.FileInfo.StoragePath;
if (path == null)
return;

View File

@ -15,7 +15,7 @@ using osu.Game.Rulesets.Mods;
namespace osu.Game.Tests.Visual
{
public abstract class OsuTestCase : TestCase
public abstract class OsuTestCase : TestScene
{
[Cached(typeof(Bindable<WorkingBeatmap>))]
[Cached(typeof(IBindable<WorkingBeatmap>))]
@ -76,21 +76,21 @@ namespace osu.Game.Tests.Visual
}
}
protected override ITestCaseTestRunner CreateRunner() => new OsuTestCaseTestRunner();
protected override ITestSceneTestRunner CreateRunner() => new OsuTestCaseTestRunner();
public class OsuTestCaseTestRunner : OsuGameBase, ITestCaseTestRunner
public class OsuTestCaseTestRunner : OsuGameBase, ITestSceneTestRunner
{
private TestCaseTestRunner.TestRunner runner;
private TestSceneTestRunner.TestRunner runner;
protected override void LoadAsyncComplete()
{
// this has to be run here rather than LoadComplete because
// TestCase.cs is checking the IsLoaded state (on another thread) and expects
// the runner to be loaded at that point.
Add(runner = new TestCaseTestRunner.TestRunner());
Add(runner = new TestSceneTestRunner.TestRunner());
}
public void RunTestBlocking(TestCase test) => runner.RunTestBlocking(test);
public void RunTestBlocking(TestScene test) => runner.RunTestBlocking(test);
}
private class OsuTestBeatmap : BindableBeatmap

View File

@ -15,7 +15,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.4" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.502.0" />
<PackageReference Include="ppy.osu.Framework" Version="2019.508.0" />
<PackageReference Include="ppy.osu.Framework" Version="2019.514.0" />
<PackageReference Include="SharpCompress" Version="0.23.0" />
<PackageReference Include="NUnit" Version="3.11.0" />
<PackageReference Include="SharpRaven" Version="2.4.0" />

View File

@ -105,8 +105,8 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.1" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.128.0" />
<PackageReference Include="ppy.osu.Framework" Version="2019.502.0" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2019.502.0" />
<PackageReference Include="ppy.osu.Framework" Version="2019.514.0" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2019.514.0" />
<PackageReference Include="SharpCompress" Version="0.22.0" />
<PackageReference Include="NUnit" Version="3.11.0" />
<PackageReference Include="SharpRaven" Version="2.4.0" />

View File

@ -9,7 +9,7 @@ namespace osu.iOS
{
public static void Main(string[] args)
{
UIApplication.Main(args, null, "AppDelegate");
UIApplication.Main(args, "GameUIApplication", "AppDelegate");
}
}
}