Merge remote-tracking branch 'refs/remotes/ppy/master' into subcomments-alter-new
30
README.md
@ -13,25 +13,17 @@ Rhythm is just a *click* away. The future of [osu!](https://osu.ppy.sh) and the
|
||||
|
||||
## Status
|
||||
|
||||
This project is still heavily under development, but is in a state where users are encouraged to try it out and keep it installed alongside the stable *osu!* client. It will continue to evolve over the coming months and hopefully bring some new unique features to the table.
|
||||
This project is under heavy development, but is in a stable state. Users are encouraged to try it out and keep it installed alongside the stable *osu!* client. It will continue to evolve to the point of eventually replacing the existing stable client as an update.
|
||||
|
||||
We are accepting bug reports (please report with as much detail as possible). Feature requests are welcome as long as you read and understand the contribution guidelines listed below.
|
||||
We are accepting bug reports (please report with as much detail as possible). Feature requests are also welcome, but understand that our focus is on completing the game to feature parity before adding new features. A few resources are available as starting points to getting involved and understanding the project:
|
||||
|
||||
Detailed changelogs are published on the [official osu! site](https://osu.ppy.sh/home/changelog).
|
||||
|
||||
## Requirements
|
||||
|
||||
- A desktop platform with the [.NET Core 3.1 SDK](https://dotnet.microsoft.com/download) or higher installed.
|
||||
- When running on Linux, please have a system-wide FFmpeg installation available to support video decoding.
|
||||
- When running on Windows 7 or 8.1, **[additional prerequisites](https://docs.microsoft.com/en-us/dotnet/core/install/dependencies?tabs=netcore31&pivots=os-windows)** may be required to correctly run .NET Core applications if your operating system is not up-to-date with the latest service packs.
|
||||
- When developing with mobile, [Xamarin](https://docs.microsoft.com/en-us/xamarin/) is required, which is shipped together with Visual Studio or [Visual Studio for Mac](https://visualstudio.microsoft.com/vs/mac/).
|
||||
- When working with the codebase, we recommend using an IDE with intelligent code completion and syntax highlighting, such as [Visual Studio 2019+](https://visualstudio.microsoft.com/vs/), [JetBrains Rider](https://www.jetbrains.com/rider/) or [Visual Studio Code](https://code.visualstudio.com/).
|
||||
- Detailed release changelogs are available on the [official osu! site](https://osu.ppy.sh/home/changelog/lazer).
|
||||
- You can learn more about our approach to [project management](https://github.com/ppy/osu/wiki/Project-management).
|
||||
- Read peppy's [latest blog post](https://blog.ppy.sh/a-definitive-lazer-faq/) exploring where lazer is currently and the roadmap going forward.
|
||||
|
||||
## Running osu!
|
||||
|
||||
### Releases
|
||||
|
||||
If you are not interested in developing the game, you can still consume our [binary releases](https://github.com/ppy/osu/releases).
|
||||
If you are looking to install or test osu! without setting up a development environment, you can consume our [binary releases](https://github.com/ppy/osu/releases). Handy links below will download the latest version for your operating system of choice:
|
||||
|
||||
**Latest build:**
|
||||
|
||||
@ -39,9 +31,19 @@ If you are not interested in developing the game, you can still consume our [bin
|
||||
| ------------- | ------------- | ------------- | ------------- |
|
||||
|
||||
- **Linux** users are recommended to self-compile until we have official deployment in place.
|
||||
- When running on Windows 7 or 8.1, **[additional prerequisites](https://docs.microsoft.com/en-us/dotnet/core/install/dependencies?tabs=netcore31&pivots=os-windows)** may be required to correctly run .NET Core applications if your operating system is not up-to-date with the latest service packs.
|
||||
|
||||
If your platform is not listed above, there is still a chance you can manually build it by following the instructions below.
|
||||
|
||||
## Developing or debugging
|
||||
|
||||
Please make sure you have the following prerequisites:
|
||||
|
||||
- A desktop platform with the [.NET Core 3.1 SDK](https://dotnet.microsoft.com/download) or higher installed.
|
||||
- When developing with mobile, [Xamarin](https://docs.microsoft.com/en-us/xamarin/) is required, which is shipped together with Visual Studio or [Visual Studio for Mac](https://visualstudio.microsoft.com/vs/mac/).
|
||||
- When working with the codebase, we recommend using an IDE with intelligent code completion and syntax highlighting, such as [Visual Studio 2019+](https://visualstudio.microsoft.com/vs/), [JetBrains Rider](https://www.jetbrains.com/rider/) or [Visual Studio Code](https://code.visualstudio.com/).
|
||||
- When running on Linux, please have a system-wide FFmpeg installation available to support video decoding.
|
||||
|
||||
### Downloading the source code
|
||||
|
||||
Clone the repository:
|
||||
|
@ -1,5 +1,5 @@
|
||||
#addin "nuget:?package=CodeFileSanity&version=0.0.33"
|
||||
#addin "nuget:?package=JetBrains.ReSharper.CommandLineTools&version=2019.3.0"
|
||||
#addin "nuget:?package=JetBrains.ReSharper.CommandLineTools&version=2019.3.2"
|
||||
#tool "nuget:?package=NVika.MSBuild&version=1.0.1"
|
||||
var nVikaToolPath = GetFiles("./tools/NVika.MSBuild.*/tools/NVika.exe").First();
|
||||
|
||||
|
@ -54,6 +54,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.1230.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.213.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.218.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 4.9 KiB |
BIN
osu.Game.Rulesets.Catch.Tests/Resources/old-skin/fruit-apple.png
Normal file
After Width: | Height: | Size: 5.0 KiB |
BIN
osu.Game.Rulesets.Catch.Tests/Resources/old-skin/fruit-drop.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 3.9 KiB |
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 8.8 KiB |
After Width: | Height: | Size: 7.0 KiB |
BIN
osu.Game.Rulesets.Catch.Tests/Resources/old-skin/fruit-pear.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
osu.Game.Rulesets.Catch.Tests/Resources/old-skin/fruit-plate.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 11 KiB |
BIN
osu.Game.Rulesets.Catch.Tests/Resources/old-skin/hit0.png
Normal file
After Width: | Height: | Size: 9.3 KiB |
BIN
osu.Game.Rulesets.Catch.Tests/Resources/old-skin/hit100.png
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
osu.Game.Rulesets.Catch.Tests/Resources/old-skin/hit300.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
osu.Game.Rulesets.Catch.Tests/Resources/old-skin/hit50.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
osu.Game.Rulesets.Catch.Tests/Resources/special-skin/fruit-apple-overlay.png
Executable file
After Width: | Height: | Size: 4.6 KiB |
BIN
osu.Game.Rulesets.Catch.Tests/Resources/special-skin/fruit-apple.png
Executable file
After Width: | Height: | Size: 4.6 KiB |
BIN
osu.Game.Rulesets.Catch.Tests/Resources/special-skin/fruit-bananas-overlay.png
Executable file
After Width: | Height: | Size: 4.8 KiB |
BIN
osu.Game.Rulesets.Catch.Tests/Resources/special-skin/fruit-bananas.png
Executable file
After Width: | Height: | Size: 4.8 KiB |
BIN
osu.Game.Rulesets.Catch.Tests/Resources/special-skin/fruit-catcher-fail.png
Executable file
After Width: | Height: | Size: 62 KiB |
BIN
osu.Game.Rulesets.Catch.Tests/Resources/special-skin/fruit-catcher-idle.png
Executable file
After Width: | Height: | Size: 130 KiB |
BIN
osu.Game.Rulesets.Catch.Tests/Resources/special-skin/fruit-catcher-kiai.png
Executable file
After Width: | Height: | Size: 36 KiB |
BIN
osu.Game.Rulesets.Catch.Tests/Resources/special-skin/fruit-drop-overlay.png
Executable file
After Width: | Height: | Size: 4.6 KiB |
BIN
osu.Game.Rulesets.Catch.Tests/Resources/special-skin/fruit-drop.png
Executable file
After Width: | Height: | Size: 4.6 KiB |
BIN
osu.Game.Rulesets.Catch.Tests/Resources/special-skin/fruit-grapes-overlay.png
Executable file
After Width: | Height: | Size: 4.6 KiB |
BIN
osu.Game.Rulesets.Catch.Tests/Resources/special-skin/fruit-grapes.png
Executable file
After Width: | Height: | Size: 4.5 KiB |
BIN
osu.Game.Rulesets.Catch.Tests/Resources/special-skin/fruit-orange-overlay.png
Executable file
After Width: | Height: | Size: 4.5 KiB |
BIN
osu.Game.Rulesets.Catch.Tests/Resources/special-skin/fruit-orange.png
Executable file
After Width: | Height: | Size: 4.5 KiB |
BIN
osu.Game.Rulesets.Catch.Tests/Resources/special-skin/fruit-pear-overlay.png
Executable file
After Width: | Height: | Size: 4.5 KiB |
BIN
osu.Game.Rulesets.Catch.Tests/Resources/special-skin/fruit-pear.png
Executable file
After Width: | Height: | Size: 4.5 KiB |
@ -3,104 +3,31 @@
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Catch.UI;
|
||||
using osu.Game.Tests.Visual;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osuTK.Graphics;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Framework.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneCatcher : OsuTestScene
|
||||
public class TestSceneCatcher : SkinnableTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(CatcherSprite),
|
||||
typeof(CatcherArea),
|
||||
};
|
||||
|
||||
private readonly Container container;
|
||||
|
||||
public TestSceneCatcher()
|
||||
{
|
||||
Child = container = new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
AddStep("show default catcher implementation", () => { container.Child = new CatcherSprite(); });
|
||||
|
||||
AddStep("show custom catcher implementation", () =>
|
||||
SetContents(() => new CatcherArea.Catcher
|
||||
{
|
||||
container.Child = new CatchCustomSkinSourceContainer
|
||||
{
|
||||
Child = new CatcherSprite()
|
||||
};
|
||||
RelativePositionAxes = Axes.None,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
});
|
||||
}
|
||||
|
||||
private class CatcherCustomSkin : Container
|
||||
{
|
||||
public CatcherCustomSkin()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Blue
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = "custom"
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Cached(typeof(ISkinSource))]
|
||||
private class CatchCustomSkinSourceContainer : Container, ISkinSource
|
||||
{
|
||||
public event Action SourceChanged
|
||||
{
|
||||
add { }
|
||||
remove { }
|
||||
}
|
||||
|
||||
public Drawable GetDrawableComponent(ISkinComponent component)
|
||||
{
|
||||
switch (component.LookupName)
|
||||
{
|
||||
case "Gameplay/catch/fruit-catcher-idle":
|
||||
return new CatcherCustomSkin();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public SampleChannel GetSample(ISampleInfo sampleInfo) =>
|
||||
throw new NotImplementedException();
|
||||
|
||||
public Texture GetTexture(string componentName) =>
|
||||
throw new NotImplementedException();
|
||||
|
||||
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,10 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Catch.UI;
|
||||
@ -13,10 +15,9 @@ using osu.Game.Tests.Visual;
|
||||
namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneCatcherArea : OsuTestScene
|
||||
public class TestSceneCatcherArea : SkinnableTestScene
|
||||
{
|
||||
private RulesetInfo catchRuleset;
|
||||
private TestCatcherArea catcherArea;
|
||||
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
@ -26,20 +27,22 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
public TestSceneCatcherArea()
|
||||
{
|
||||
AddSliderStep<float>("CircleSize", 0, 8, 5, createCatcher);
|
||||
AddToggleStep("Hyperdash", t => catcherArea.ToggleHyperDash(t));
|
||||
AddToggleStep("Hyperdash", t =>
|
||||
CreatedDrawables.OfType<CatchInputManager>().Select(i => i.Child)
|
||||
.OfType<TestCatcherArea>().ForEach(c => c.ToggleHyperDash(t)));
|
||||
}
|
||||
|
||||
private void createCatcher(float size)
|
||||
{
|
||||
Child = new CatchInputManager(catchRuleset)
|
||||
SetContents(() => new CatchInputManager(catchRuleset)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = catcherArea = new TestCatcherArea(new BeatmapDifficulty { CircleSize = size })
|
||||
Child = new TestCatcherArea(new BeatmapDifficulty { CircleSize = size })
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.TopLeft
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
|
@ -5,7 +5,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Catch.Objects.Drawable;
|
||||
using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces;
|
||||
@ -15,68 +14,58 @@ using osuTK;
|
||||
namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneFruitObjects : OsuTestScene
|
||||
public class TestSceneFruitObjects : SkinnableTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(CatchHitObject),
|
||||
typeof(Fruit),
|
||||
typeof(Droplet),
|
||||
typeof(Banana),
|
||||
typeof(BananaShower),
|
||||
typeof(DrawableCatchHitObject),
|
||||
typeof(DrawableFruit),
|
||||
typeof(DrawableDroplet),
|
||||
typeof(BananaShower),
|
||||
typeof(DrawableBanana),
|
||||
typeof(DrawableBananaShower),
|
||||
typeof(Pulp),
|
||||
};
|
||||
|
||||
public TestSceneFruitObjects()
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
Add(new GridContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Content = new[]
|
||||
{
|
||||
new Drawable[]
|
||||
{
|
||||
createDrawable(0),
|
||||
createDrawable(1),
|
||||
createDrawable(2),
|
||||
},
|
||||
new Drawable[]
|
||||
{
|
||||
createDrawable(3),
|
||||
createDrawable(4),
|
||||
createDrawable(5),
|
||||
},
|
||||
}
|
||||
});
|
||||
base.LoadComplete();
|
||||
|
||||
foreach (FruitVisualRepresentation rep in Enum.GetValues(typeof(FruitVisualRepresentation)))
|
||||
AddStep($"show {rep}", () => SetContents(() => createDrawable(rep)));
|
||||
}
|
||||
|
||||
private DrawableFruit createDrawable(int index)
|
||||
private DrawableFruit createDrawable(FruitVisualRepresentation rep)
|
||||
{
|
||||
Fruit fruit = index == 5
|
||||
? new Banana
|
||||
{
|
||||
StartTime = 1000000000000,
|
||||
IndexInBeatmap = index,
|
||||
Scale = 1.5f,
|
||||
}
|
||||
: new Fruit
|
||||
{
|
||||
StartTime = 1000000000000,
|
||||
IndexInBeatmap = index,
|
||||
Scale = 1.5f,
|
||||
};
|
||||
Fruit fruit = new TestCatchFruit(rep)
|
||||
{
|
||||
StartTime = 1000000000000,
|
||||
Scale = 1.5f,
|
||||
};
|
||||
|
||||
return new DrawableFruit(fruit)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
RelativePositionAxes = Axes.Both,
|
||||
RelativePositionAxes = Axes.None,
|
||||
Position = Vector2.Zero,
|
||||
Alpha = 1,
|
||||
LifetimeStart = double.NegativeInfinity,
|
||||
LifetimeEnd = double.PositiveInfinity,
|
||||
};
|
||||
}
|
||||
|
||||
private class TestCatchFruit : Fruit
|
||||
{
|
||||
public TestCatchFruit(FruitVisualRepresentation rep)
|
||||
{
|
||||
VisualRepresentation = rep;
|
||||
}
|
||||
|
||||
public override FruitVisualRepresentation VisualRepresentation { get; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
Samples = tickSamples,
|
||||
StartTime = t + lastEvent.Value.Time,
|
||||
X = X + Path.PositionAt(
|
||||
lastEvent.Value.PathProgress + (t / sinceLastTick) * (e.PathProgress - lastEvent.Value.PathProgress)).X / CatchPlayfield.BASE_WIDTH,
|
||||
lastEvent.Value.PathProgress + (t / sinceLastTick) * (e.PathProgress - lastEvent.Value.PathProgress)).X / CatchPlayfield.BASE_WIDTH,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -63,6 +63,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
if (result.IsHit && fruit.CanBePlated)
|
||||
{
|
||||
// create a new (cloned) fruit to stay on the plate. the original is faded out immediately.
|
||||
var caughtFruit = (DrawableCatchHitObject)CreateDrawableRepresentation?.Invoke(fruit.HitObject);
|
||||
|
||||
if (caughtFruit == null) return;
|
||||
@ -133,7 +134,6 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
X = 0.5f;
|
||||
|
||||
Origin = Anchor.TopCentre;
|
||||
Anchor = Anchor.TopLeft;
|
||||
|
||||
Size = new Vector2(CATCHER_SIZE);
|
||||
if (difficulty != null)
|
||||
@ -388,32 +388,24 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdatePosition(float position)
|
||||
{
|
||||
position = Math.Clamp(position, 0, 1);
|
||||
|
||||
if (position == X)
|
||||
return;
|
||||
|
||||
Scale = new Vector2(Math.Abs(Scale.X) * (position > X ? 1 : -1), Scale.Y);
|
||||
X = position;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drop any fruit off the plate.
|
||||
/// </summary>
|
||||
public void Drop()
|
||||
{
|
||||
var fruit = caughtFruit.ToArray();
|
||||
|
||||
foreach (var f in fruit)
|
||||
{
|
||||
if (ExplodingFruitTarget != null)
|
||||
{
|
||||
f.Anchor = Anchor.TopLeft;
|
||||
f.Position = caughtFruit.ToSpaceOfOtherDrawable(f.DrawPosition, ExplodingFruitTarget);
|
||||
|
||||
caughtFruit.Remove(f);
|
||||
|
||||
ExplodingFruitTarget.Add(f);
|
||||
}
|
||||
|
||||
f.MoveToY(f.Y + 75, 750, Easing.InSine);
|
||||
f.FadeOut(750);
|
||||
|
||||
// todo: this shouldn't exist once DrawableHitObject's ClearTransformsAfter overrides are repaired.
|
||||
f.LifetimeStart = Time.Current;
|
||||
f.Expire();
|
||||
}
|
||||
foreach (var f in caughtFruit.ToArray())
|
||||
Drop(f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -425,10 +417,26 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
Explode(f);
|
||||
}
|
||||
|
||||
public void Drop(DrawableHitObject fruit) => removeFromPlateWithTransform(fruit, f =>
|
||||
{
|
||||
f.MoveToY(f.Y + 75, 750, Easing.InSine);
|
||||
f.FadeOut(750);
|
||||
});
|
||||
|
||||
public void Explode(DrawableHitObject fruit)
|
||||
{
|
||||
var originalX = fruit.X * Scale.X;
|
||||
|
||||
removeFromPlateWithTransform(fruit, f =>
|
||||
{
|
||||
f.MoveToY(f.Y - 50, 250, Easing.OutSine).Then().MoveToY(f.Y + 50, 500, Easing.InSine);
|
||||
f.MoveToX(f.X + originalX * 6, 1000);
|
||||
f.FadeOut(750);
|
||||
});
|
||||
}
|
||||
|
||||
private void removeFromPlateWithTransform(DrawableHitObject fruit, Action<DrawableHitObject> action)
|
||||
{
|
||||
if (ExplodingFruitTarget != null)
|
||||
{
|
||||
fruit.Anchor = Anchor.TopLeft;
|
||||
@ -442,25 +450,18 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
ExplodingFruitTarget.Add(fruit);
|
||||
}
|
||||
|
||||
fruit.ClearTransforms();
|
||||
fruit.MoveToY(fruit.Y - 50, 250, Easing.OutSine).Then().MoveToY(fruit.Y + 50, 500, Easing.InSine);
|
||||
fruit.MoveToX(fruit.X + originalX * 6, 1000);
|
||||
fruit.FadeOut(750);
|
||||
double actionTime = Clock.CurrentTime;
|
||||
|
||||
// todo: this shouldn't exist once DrawableHitObject's ClearTransformsAfter overrides are repaired.
|
||||
fruit.LifetimeStart = Time.Current;
|
||||
fruit.Expire();
|
||||
}
|
||||
fruit.ApplyCustomUpdateState += onFruitOnApplyCustomUpdateState;
|
||||
onFruitOnApplyCustomUpdateState(fruit, fruit.State.Value);
|
||||
|
||||
public void UpdatePosition(float position)
|
||||
{
|
||||
position = Math.Clamp(position, 0, 1);
|
||||
void onFruitOnApplyCustomUpdateState(DrawableHitObject o, ArmedState state)
|
||||
{
|
||||
using (fruit.BeginAbsoluteSequence(actionTime))
|
||||
action(fruit);
|
||||
|
||||
if (position == X)
|
||||
return;
|
||||
|
||||
Scale = new Vector2(Math.Abs(Scale.X) * (position > X ? 1 : -1), Scale.Y);
|
||||
X = position;
|
||||
fruit.Expire();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,85 +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 System;
|
||||
using System.Text.RegularExpressions;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.IO.Stores;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
public abstract class SkinnableTestScene : OsuGridTestScene
|
||||
{
|
||||
private Skin metricsSkin;
|
||||
private Skin defaultSkin;
|
||||
private Skin specialSkin;
|
||||
private Skin oldSkin;
|
||||
|
||||
protected SkinnableTestScene()
|
||||
: base(2, 3)
|
||||
{
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio, SkinManager skinManager)
|
||||
{
|
||||
var dllStore = new DllResourceStore(typeof(SkinnableTestScene).Assembly);
|
||||
|
||||
metricsSkin = new TestLegacySkin(new SkinInfo(), new NamespacedResourceStore<byte[]>(dllStore, "Resources/metrics_skin"), audio, true);
|
||||
defaultSkin = skinManager.GetSkin(DefaultLegacySkin.Info);
|
||||
specialSkin = new TestLegacySkin(new SkinInfo(), new NamespacedResourceStore<byte[]>(dllStore, "Resources/special_skin"), audio, true);
|
||||
oldSkin = new TestLegacySkin(new SkinInfo(), new NamespacedResourceStore<byte[]>(dllStore, "Resources/old_skin"), audio, true);
|
||||
}
|
||||
|
||||
public void SetContents(Func<Drawable> creationFunction)
|
||||
{
|
||||
Cell(0).Child = createProvider(null, creationFunction);
|
||||
Cell(1).Child = createProvider(metricsSkin, creationFunction);
|
||||
Cell(2).Child = createProvider(defaultSkin, creationFunction);
|
||||
Cell(3).Child = createProvider(specialSkin, creationFunction);
|
||||
Cell(4).Child = createProvider(oldSkin, creationFunction);
|
||||
}
|
||||
|
||||
private Drawable createProvider(Skin skin, Func<Drawable> creationFunction)
|
||||
{
|
||||
var mainProvider = new SkinProvidingContainer(skin);
|
||||
|
||||
return mainProvider
|
||||
.WithChild(new SkinProvidingContainer(Ruleset.Value.CreateInstance().CreateLegacySkinProvider(mainProvider))
|
||||
{
|
||||
Child = creationFunction()
|
||||
});
|
||||
}
|
||||
|
||||
private class TestLegacySkin : LegacySkin
|
||||
{
|
||||
private readonly bool extrapolateAnimations;
|
||||
|
||||
public TestLegacySkin(SkinInfo skin, IResourceStore<byte[]> storage, AudioManager audioManager, bool extrapolateAnimations)
|
||||
: base(skin, storage, audioManager, "skin.ini")
|
||||
{
|
||||
this.extrapolateAnimations = extrapolateAnimations;
|
||||
}
|
||||
|
||||
public override Texture GetTexture(string componentName)
|
||||
{
|
||||
// extrapolate frames to test longer animations
|
||||
if (extrapolateAnimations)
|
||||
{
|
||||
var match = Regex.Match(componentName, "-([0-9]*)");
|
||||
|
||||
if (match.Length > 0 && int.TryParse(match.Groups[1].Value, out var number) && number < 60)
|
||||
return base.GetTexture(componentName.Replace($"-{number}", $"-{number % 2}"));
|
||||
}
|
||||
|
||||
return base.GetTexture(componentName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -10,6 +10,7 @@ using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
|
@ -10,6 +10,7 @@ using osu.Framework.Testing.Input;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets.Osu.UI.Cursor;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests
|
||||
|
@ -14,6 +14,7 @@ using osu.Game.Rulesets.Mods;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
|
@ -22,6 +22,7 @@ using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
|
@ -9,6 +9,7 @@ using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using static osu.Game.Input.Handlers.ReplayInputHandler;
|
||||
|
||||
@ -24,6 +25,21 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
/// </summary>
|
||||
private const float relax_leniency = 3;
|
||||
|
||||
private bool isDownState;
|
||||
private bool wasLeft;
|
||||
|
||||
private OsuInputManager osuInputManager;
|
||||
|
||||
private ReplayState<OsuAction> state;
|
||||
private double lastStateChangeTime;
|
||||
|
||||
public void ApplyToDrawableRuleset(DrawableRuleset<OsuHitObject> drawableRuleset)
|
||||
{
|
||||
// grab the input manager for future use.
|
||||
osuInputManager = (OsuInputManager)drawableRuleset.KeyBindingInputManager;
|
||||
osuInputManager.AllowUserPresses = false;
|
||||
}
|
||||
|
||||
public void Update(Playfield playfield)
|
||||
{
|
||||
bool requiresHold = false;
|
||||
@ -63,11 +79,14 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
|
||||
if (requiresHit)
|
||||
{
|
||||
addAction(false);
|
||||
addAction(true);
|
||||
changeState(false);
|
||||
changeState(true);
|
||||
}
|
||||
|
||||
addAction(requiresHold);
|
||||
if (requiresHold)
|
||||
changeState(true);
|
||||
else if (isDownState && time - lastStateChangeTime > AutoGenerator.KEY_UP_DELAY)
|
||||
changeState(false);
|
||||
|
||||
void handleHitCircle(DrawableHitCircle circle)
|
||||
{
|
||||
@ -77,39 +96,28 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
Debug.Assert(circle.HitObject.HitWindows != null);
|
||||
requiresHit |= circle.HitObject.HitWindows.CanBeHit(time - circle.HitObject.StartTime);
|
||||
}
|
||||
}
|
||||
|
||||
private bool wasHit;
|
||||
private bool wasLeft;
|
||||
|
||||
private OsuInputManager osuInputManager;
|
||||
|
||||
private void addAction(bool hitting)
|
||||
{
|
||||
if (wasHit == hitting)
|
||||
return;
|
||||
|
||||
wasHit = hitting;
|
||||
|
||||
var state = new ReplayState<OsuAction>
|
||||
void changeState(bool down)
|
||||
{
|
||||
PressedActions = new List<OsuAction>()
|
||||
};
|
||||
if (isDownState == down)
|
||||
return;
|
||||
|
||||
if (hitting)
|
||||
{
|
||||
state.PressedActions.Add(wasLeft ? OsuAction.LeftButton : OsuAction.RightButton);
|
||||
wasLeft = !wasLeft;
|
||||
isDownState = down;
|
||||
lastStateChangeTime = time;
|
||||
|
||||
state = new ReplayState<OsuAction>
|
||||
{
|
||||
PressedActions = new List<OsuAction>()
|
||||
};
|
||||
|
||||
if (down)
|
||||
{
|
||||
state.PressedActions.Add(wasLeft ? OsuAction.LeftButton : OsuAction.RightButton);
|
||||
wasLeft = !wasLeft;
|
||||
}
|
||||
|
||||
state?.Apply(osuInputManager.CurrentState, osuInputManager);
|
||||
}
|
||||
|
||||
state.Apply(osuInputManager.CurrentState, osuInputManager);
|
||||
}
|
||||
|
||||
public void ApplyToDrawableRuleset(DrawableRuleset<OsuHitObject> drawableRuleset)
|
||||
{
|
||||
// grab the input manager for future use.
|
||||
osuInputManager = (OsuInputManager)drawableRuleset.KeyBindingInputManager;
|
||||
osuInputManager.AllowUserPresses = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Mods
|
||||
@ -27,26 +28,40 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
public void ApplyToDrawableHitObjects(IEnumerable<DrawableHitObject> drawables)
|
||||
{
|
||||
foreach (var drawable in drawables)
|
||||
drawable.ApplyCustomUpdateState += applyTransform;
|
||||
}
|
||||
|
||||
private void applyTransform(DrawableHitObject drawable, ArmedState state)
|
||||
{
|
||||
switch (drawable)
|
||||
{
|
||||
var hitObject = (OsuHitObject)drawable.HitObject;
|
||||
case DrawableSliderHead _:
|
||||
case DrawableSliderTail _:
|
||||
case DrawableSliderTick _:
|
||||
case DrawableRepeatPoint _:
|
||||
return;
|
||||
|
||||
float appearDistance = (float)(hitObject.TimePreempt - hitObject.TimeFadeIn) / 2;
|
||||
default:
|
||||
var hitObject = (OsuHitObject)drawable.HitObject;
|
||||
|
||||
Vector2 originalPosition = drawable.Position;
|
||||
Vector2 appearOffset = new Vector2(MathF.Cos(theta), MathF.Sin(theta)) * appearDistance;
|
||||
float appearDistance = (float)(hitObject.TimePreempt - hitObject.TimeFadeIn) / 2;
|
||||
|
||||
//the - 1 and + 1 prevents the hit objects to appear in the wrong position.
|
||||
double appearTime = hitObject.StartTime - hitObject.TimePreempt - 1;
|
||||
double moveDuration = hitObject.TimePreempt + 1;
|
||||
Vector2 originalPosition = drawable.Position;
|
||||
Vector2 appearOffset = new Vector2(MathF.Cos(theta), MathF.Sin(theta)) * appearDistance;
|
||||
|
||||
using (drawable.BeginAbsoluteSequence(appearTime, true))
|
||||
{
|
||||
drawable
|
||||
.MoveToOffset(appearOffset)
|
||||
.MoveTo(originalPosition, moveDuration, Easing.InOutSine);
|
||||
}
|
||||
//the - 1 and + 1 prevents the hit objects to appear in the wrong position.
|
||||
double appearTime = hitObject.StartTime - hitObject.TimePreempt - 1;
|
||||
double moveDuration = hitObject.TimePreempt + 1;
|
||||
|
||||
theta += (float)hitObject.TimeFadeIn / 1000;
|
||||
using (drawable.BeginAbsoluteSequence(appearTime, true))
|
||||
{
|
||||
drawable
|
||||
.MoveToOffset(appearOffset)
|
||||
.MoveTo(originalPosition, moveDuration, Easing.InOutSine);
|
||||
}
|
||||
|
||||
theta += (float)hitObject.TimeFadeIn / 1000;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -116,8 +116,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
|
||||
public Slider()
|
||||
{
|
||||
SamplesBindable.ItemsAdded += _ => updateNestedSamples();
|
||||
SamplesBindable.ItemsRemoved += _ => updateNestedSamples();
|
||||
SamplesBindable.CollectionChanged += (_, __) => updateNestedSamples();
|
||||
Path.Version.ValueChanged += _ => updateNestedPositions();
|
||||
}
|
||||
|
||||
|
BIN
osu.Game.Tests/Resources/Archives/ogg-beatmap.osz
Normal file
BIN
osu.Game.Tests/Resources/Archives/ogg-skin.osk
Normal file
37
osu.Game.Tests/Skins/TestSceneBeatmapSkinResources.cs
Normal file
@ -0,0 +1,37 @@
|
||||
// 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.Allocation;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.IO.Archives;
|
||||
using osu.Game.Tests.Resources;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Tests.Skins
|
||||
{
|
||||
[HeadlessTest]
|
||||
public class TestSceneBeatmapSkinResources : OsuTestScene
|
||||
{
|
||||
[Resolved]
|
||||
private BeatmapManager beatmaps { get; set; }
|
||||
|
||||
private WorkingBeatmap beatmap;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
var imported = beatmaps.Import(new ZipArchiveReader(TestResources.OpenResource("Archives/ogg-beatmap.osz"))).Result;
|
||||
beatmap = beatmaps.GetWorkingBeatmap(imported.Beatmaps[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRetrieveOggSample() => AddAssert("sample is non-null", () => beatmap.Skin.GetSample(new SampleInfo("sample")) != null);
|
||||
|
||||
[Test]
|
||||
public void TestRetrieveOggTrack() => AddAssert("track is non-null", () => !(beatmap.Track is TrackVirtual));
|
||||
}
|
||||
}
|
33
osu.Game.Tests/Skins/TestSceneSkinResources.cs
Normal file
@ -0,0 +1,33 @@
|
||||
// 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.Allocation;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.IO.Archives;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Tests.Resources;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Tests.Skins
|
||||
{
|
||||
[HeadlessTest]
|
||||
public class TestSceneSkinResources : OsuTestScene
|
||||
{
|
||||
[Resolved]
|
||||
private SkinManager skins { get; set; }
|
||||
|
||||
private ISkin skin;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
var imported = skins.Import(new ZipArchiveReader(TestResources.OpenResource("Archives/ogg-skin.osk"))).Result;
|
||||
skin = skins.GetSkin(imported);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRetrieveOggSample() => AddAssert("sample is non-null", () => skin.GetSample(new SampleInfo("sample")) != null);
|
||||
}
|
||||
}
|
@ -91,9 +91,44 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
AddStep("load dummy beatmap", () => ResetPlayer(false));
|
||||
AddUntilStep("wait for current", () => loader.IsCurrentScreen());
|
||||
AddRepeatStep("move mouse", () => InputManager.MoveMouseTo(loader.VisualSettings.ScreenSpaceDrawQuad.TopLeft + (loader.VisualSettings.ScreenSpaceDrawQuad.BottomRight - loader.VisualSettings.ScreenSpaceDrawQuad.TopLeft) * RNG.NextSingle()), 20);
|
||||
|
||||
AddUntilStep("wait for load ready", () =>
|
||||
{
|
||||
moveMouse();
|
||||
return player.LoadState == LoadState.Ready;
|
||||
});
|
||||
AddRepeatStep("move mouse", moveMouse, 20);
|
||||
|
||||
AddAssert("loader still active", () => loader.IsCurrentScreen());
|
||||
AddUntilStep("loads after idle", () => !loader.IsCurrentScreen());
|
||||
|
||||
void moveMouse()
|
||||
{
|
||||
InputManager.MoveMouseTo(
|
||||
loader.VisualSettings.ScreenSpaceDrawQuad.TopLeft
|
||||
+ (loader.VisualSettings.ScreenSpaceDrawQuad.BottomRight - loader.VisualSettings.ScreenSpaceDrawQuad.TopLeft)
|
||||
* RNG.NextSingle());
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBlockLoadViaFocus()
|
||||
{
|
||||
OsuFocusedOverlayContainer overlay = null;
|
||||
|
||||
AddStep("load dummy beatmap", () => ResetPlayer(false));
|
||||
AddUntilStep("wait for current", () => loader.IsCurrentScreen());
|
||||
|
||||
AddStep("show focused overlay", () => { container.Add(overlay = new ChangelogOverlay { State = { Value = Visibility.Visible } }); });
|
||||
AddUntilStep("overlay visible", () => overlay.IsPresent);
|
||||
|
||||
AddUntilStep("wait for load ready", () => player.LoadState == LoadState.Ready);
|
||||
AddRepeatStep("twiddle thumbs", () => { }, 20);
|
||||
|
||||
AddAssert("loader still active", () => loader.IsCurrentScreen());
|
||||
|
||||
AddStep("hide overlay", () => overlay.Hide());
|
||||
AddUntilStep("loads after idle", () => !loader.IsCurrentScreen());
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -159,13 +194,22 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMutedNotificationMasterVolume() => addVolumeSteps("master volume", () => audioManager.Volume.Value = 0, null, () => audioManager.Volume.IsDefault);
|
||||
public void TestMutedNotificationMasterVolume()
|
||||
{
|
||||
addVolumeSteps("master volume", () => audioManager.Volume.Value = 0, null, () => audioManager.Volume.IsDefault);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMutedNotificationTrackVolume() => addVolumeSteps("music volume", () => audioManager.VolumeTrack.Value = 0, null, () => audioManager.VolumeTrack.IsDefault);
|
||||
public void TestMutedNotificationTrackVolume()
|
||||
{
|
||||
addVolumeSteps("music volume", () => audioManager.VolumeTrack.Value = 0, null, () => audioManager.VolumeTrack.IsDefault);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMutedNotificationMuteButton() => addVolumeSteps("mute button", null, () => container.VolumeOverlay.IsMuted.Value = true, () => !container.VolumeOverlay.IsMuted.Value);
|
||||
public void TestMutedNotificationMuteButton()
|
||||
{
|
||||
addVolumeSteps("mute button", null, () => container.VolumeOverlay.IsMuted.Value = true, () => !container.VolumeOverlay.IsMuted.Value);
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// Created for avoiding copy pasting code for the same steps.
|
||||
@ -179,7 +223,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddStep("reset notification lock", () => sessionStatics.GetBindable<bool>(Static.MutedAudioNotificationShownOnce).Value = false);
|
||||
|
||||
AddStep("load player", () => ResetPlayer(false, beforeLoad, afterLoad));
|
||||
AddUntilStep("wait for player", () => player.IsLoaded);
|
||||
AddUntilStep("wait for player", () => player.LoadState == LoadState.Ready);
|
||||
|
||||
AddAssert("check for notification", () => container.NotificationOverlay.UnreadCount.Value == 1);
|
||||
AddStep("click notification", () =>
|
||||
@ -193,6 +237,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
});
|
||||
|
||||
AddAssert("check " + volumeName, assert);
|
||||
|
||||
AddUntilStep("wait for player load", () => player.IsLoaded);
|
||||
}
|
||||
|
||||
private class TestPlayerLoaderContainer : Container
|
||||
|
@ -0,0 +1,240 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Screens.Multi;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
using osuTK;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
public class TestSceneDrawableRoomPlaylist : ManualInputManagerTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(DrawableRoomPlaylist),
|
||||
typeof(DrawableRoomPlaylistItem)
|
||||
};
|
||||
|
||||
private DrawableRoomPlaylist playlist;
|
||||
|
||||
[Test]
|
||||
public void TestNonEditableNonSelectable()
|
||||
{
|
||||
createPlaylist(false, false);
|
||||
|
||||
moveToItem(0);
|
||||
assertHandleVisibility(0, false);
|
||||
assertDeleteButtonVisibility(0, false);
|
||||
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
AddAssert("no item selected", () => playlist.SelectedItem.Value == null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestEditable()
|
||||
{
|
||||
createPlaylist(true, false);
|
||||
|
||||
moveToItem(0);
|
||||
assertHandleVisibility(0, true);
|
||||
assertDeleteButtonVisibility(0, true);
|
||||
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
AddAssert("no item selected", () => playlist.SelectedItem.Value == null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSelectable()
|
||||
{
|
||||
createPlaylist(false, true);
|
||||
|
||||
moveToItem(0);
|
||||
assertHandleVisibility(0, false);
|
||||
assertDeleteButtonVisibility(0, false);
|
||||
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
|
||||
AddAssert("item 0 is selected", () => playlist.SelectedItem.Value == playlist.Items[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestEditableSelectable()
|
||||
{
|
||||
createPlaylist(true, true);
|
||||
|
||||
moveToItem(0);
|
||||
assertHandleVisibility(0, true);
|
||||
assertDeleteButtonVisibility(0, true);
|
||||
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
|
||||
AddAssert("item 0 is selected", () => playlist.SelectedItem.Value == playlist.Items[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSelectionNotLostAfterRearrangement()
|
||||
{
|
||||
createPlaylist(true, true);
|
||||
|
||||
moveToItem(0);
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
|
||||
moveToDragger(0);
|
||||
AddStep("begin drag", () => InputManager.PressButton(MouseButton.Left));
|
||||
moveToDragger(1, new Vector2(0, 5));
|
||||
AddStep("end drag", () => InputManager.ReleaseButton(MouseButton.Left));
|
||||
|
||||
AddAssert("item 1 is selected", () => playlist.SelectedItem.Value == playlist.Items[1]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestItemRemovedOnDeletion()
|
||||
{
|
||||
PlaylistItem selectedItem = null;
|
||||
|
||||
createPlaylist(true, true);
|
||||
|
||||
moveToItem(0);
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
AddStep("retrieve selection", () => selectedItem = playlist.SelectedItem.Value);
|
||||
|
||||
moveToDeleteButton(0);
|
||||
AddStep("click delete button", () => InputManager.Click(MouseButton.Left));
|
||||
|
||||
AddAssert("item removed", () => !playlist.Items.Contains(selectedItem));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNextItemSelectedAfterDeletion()
|
||||
{
|
||||
createPlaylist(true, true);
|
||||
|
||||
moveToItem(0);
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
|
||||
moveToDeleteButton(0);
|
||||
AddStep("click delete button", () => InputManager.Click(MouseButton.Left));
|
||||
|
||||
AddAssert("item 0 is selected", () => playlist.SelectedItem.Value == playlist.Items[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLastItemSelectedAfterLastItemDeleted()
|
||||
{
|
||||
createPlaylist(true, true);
|
||||
|
||||
AddWaitStep("wait for flow", 5); // Items may take 1 update frame to flow. A wait count of 5 is guaranteed to result in the flow being updated as desired.
|
||||
AddStep("scroll to bottom", () => playlist.ChildrenOfType<ScrollContainer<Drawable>>().First().ScrollToEnd(false));
|
||||
|
||||
moveToItem(19);
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
|
||||
moveToDeleteButton(19);
|
||||
AddStep("click delete button", () => InputManager.Click(MouseButton.Left));
|
||||
|
||||
AddAssert("item 18 is selected", () => playlist.SelectedItem.Value == playlist.Items[18]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSelectionResetWhenAllItemsDeleted()
|
||||
{
|
||||
createPlaylist(true, true);
|
||||
|
||||
AddStep("remove all but one item", () =>
|
||||
{
|
||||
playlist.Items.RemoveRange(1, playlist.Items.Count - 1);
|
||||
});
|
||||
|
||||
moveToItem(0);
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
moveToDeleteButton(0);
|
||||
AddStep("click delete button", () => InputManager.Click(MouseButton.Left));
|
||||
|
||||
AddAssert("no item selected", () => playlist.SelectedItem.Value == null);
|
||||
}
|
||||
|
||||
// Todo: currently not possible due to bindable list shortcomings (https://github.com/ppy/osu-framework/issues/3081)
|
||||
// [Test]
|
||||
public void TestNextItemSelectedAfterExternalDeletion()
|
||||
{
|
||||
createPlaylist(true, true);
|
||||
|
||||
moveToItem(0);
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
AddStep("remove item 0", () => playlist.Items.RemoveAt(0));
|
||||
|
||||
AddAssert("item 0 is selected", () => playlist.SelectedItem.Value == playlist.Items[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestChangeBeatmapAndRemove()
|
||||
{
|
||||
createPlaylist(true, true);
|
||||
|
||||
AddStep("change beatmap of first item", () => playlist.Items[0].BeatmapID = 30);
|
||||
moveToDeleteButton(0);
|
||||
AddStep("click delete button", () => InputManager.Click(MouseButton.Left));
|
||||
}
|
||||
|
||||
private void moveToItem(int index, Vector2? offset = null)
|
||||
=> AddStep($"move mouse to item {index}", () => InputManager.MoveMouseTo(playlist.ChildrenOfType<OsuRearrangeableListItem<PlaylistItem>>().ElementAt(index), offset));
|
||||
|
||||
private void moveToDragger(int index, Vector2? offset = null) => AddStep($"move mouse to dragger {index}", () =>
|
||||
{
|
||||
var item = playlist.ChildrenOfType<OsuRearrangeableListItem<PlaylistItem>>().ElementAt(index);
|
||||
InputManager.MoveMouseTo(item.ChildrenOfType<OsuRearrangeableListItem<PlaylistItem>.PlaylistItemHandle>().Single(), offset);
|
||||
});
|
||||
|
||||
private void moveToDeleteButton(int index, Vector2? offset = null) => AddStep($"move mouse to delete button {index}", () =>
|
||||
{
|
||||
var item = playlist.ChildrenOfType<OsuRearrangeableListItem<PlaylistItem>>().ElementAt(index);
|
||||
InputManager.MoveMouseTo(item.ChildrenOfType<IconButton>().ElementAt(0), offset);
|
||||
});
|
||||
|
||||
private void assertHandleVisibility(int index, bool visible)
|
||||
=> AddAssert($"handle {index} {(visible ? "is" : "is not")} visible",
|
||||
() => (playlist.ChildrenOfType<OsuRearrangeableListItem<PlaylistItem>.PlaylistItemHandle>().ElementAt(index).Alpha > 0) == visible);
|
||||
|
||||
private void assertDeleteButtonVisibility(int index, bool visible)
|
||||
=> AddAssert($"delete button {index} {(visible ? "is" : "is not")} visible", () => (playlist.ChildrenOfType<IconButton>().ElementAt(2 + index * 2).Alpha > 0) == visible);
|
||||
|
||||
private void createPlaylist(bool allowEdit, bool allowSelection) => AddStep("create playlist", () =>
|
||||
{
|
||||
Child = playlist = new DrawableRoomPlaylist(allowEdit, allowSelection)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(500, 300)
|
||||
};
|
||||
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
playlist.Items.Add(new PlaylistItem
|
||||
{
|
||||
ID = i,
|
||||
Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo },
|
||||
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
||||
RequiredMods =
|
||||
{
|
||||
new OsuModHardRock(),
|
||||
new OsuModDoubleTime(),
|
||||
new OsuModAutoplay()
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -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 NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Screens.Multi.Components;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
public class TestSceneMatchBeatmapDetailArea : MultiplayerTestScene
|
||||
{
|
||||
[Resolved]
|
||||
private BeatmapManager beatmapManager { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private RulesetStore rulesetStore { get; set; }
|
||||
|
||||
[SetUp]
|
||||
public void Setup() => Schedule(() =>
|
||||
{
|
||||
Room.Playlist.Clear();
|
||||
|
||||
Child = new MatchBeatmapDetailArea
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(500),
|
||||
CreateNewItem = createNewItem
|
||||
};
|
||||
});
|
||||
|
||||
private void createNewItem()
|
||||
{
|
||||
Room.Playlist.Add(new PlaylistItem
|
||||
{
|
||||
ID = Room.Playlist.Count,
|
||||
Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo },
|
||||
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
||||
RequiredMods =
|
||||
{
|
||||
new OsuModHardRock(),
|
||||
new OsuModDoubleTime(),
|
||||
new OsuModAutoplay()
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,41 +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 System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Screens.Multi.Match.Components;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Audio;
|
||||
using osu.Framework.Allocation;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
[Cached(typeof(IPreviewTrackOwner))]
|
||||
public class TestSceneMatchBeatmapPanel : MultiplayerTestScene, IPreviewTrackOwner
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(MatchBeatmapPanel)
|
||||
};
|
||||
|
||||
[Resolved]
|
||||
private PreviewTrackManager previewTrackManager { get; set; }
|
||||
|
||||
public TestSceneMatchBeatmapPanel()
|
||||
{
|
||||
Add(new MatchBeatmapPanel
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
});
|
||||
|
||||
Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 1763072 } } });
|
||||
Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 2101557 } } });
|
||||
Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 1973466 } } });
|
||||
Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 2109801 } } });
|
||||
Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 1922035 } } });
|
||||
}
|
||||
}
|
||||
}
|
@ -5,10 +5,10 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Online.Multiplayer.GameTypes;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Screens.Multi.Match.Components;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
@ -45,7 +45,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
}
|
||||
});
|
||||
|
||||
Room.Type.Value = new GameTypeTimeshift();
|
||||
Room.Name.Value = "A very awesome room";
|
||||
Room.Host.Value = new User { Id = 2, Username = "peppy" };
|
||||
|
||||
Child = new Header();
|
||||
}
|
||||
|
@ -1,35 +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 System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Screens.Multi.Match.Components;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
public class TestSceneMatchHostInfo : OsuTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(HostInfo)
|
||||
};
|
||||
|
||||
private readonly Bindable<User> host = new Bindable<User>(new User { Username = "SomeHost" });
|
||||
|
||||
public TestSceneMatchHostInfo()
|
||||
{
|
||||
HostInfo hostInfo;
|
||||
|
||||
Child = hostInfo = new HostInfo
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre
|
||||
};
|
||||
|
||||
hostInfo.Host.BindTo(host);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,84 +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 System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Online.Multiplayer.RoomStatuses;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Screens.Multi.Match.Components;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneMatchInfo : MultiplayerTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(Info),
|
||||
typeof(HeaderButton),
|
||||
typeof(ReadyButton),
|
||||
typeof(MatchBeatmapPanel)
|
||||
};
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(RulesetStore rulesets)
|
||||
{
|
||||
Add(new Info());
|
||||
|
||||
AddStep(@"set name", () => Room.Name.Value = @"Room Name?");
|
||||
AddStep(@"set availability", () => Room.Availability.Value = RoomAvailability.FriendsOnly);
|
||||
AddStep(@"set status", () => Room.Status.Value = new RoomStatusPlaying());
|
||||
AddStep(@"set beatmap", () =>
|
||||
{
|
||||
Room.Playlist.Clear();
|
||||
Room.Playlist.Add(new PlaylistItem
|
||||
{
|
||||
Beatmap =
|
||||
{
|
||||
Value = new BeatmapInfo
|
||||
{
|
||||
StarDifficulty = 2.4,
|
||||
Ruleset = rulesets.GetRuleset(0),
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Title = @"My Song",
|
||||
Artist = @"VisualTests",
|
||||
AuthorString = @"osu!lazer",
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
AddStep(@"change name", () => Room.Name.Value = @"Room Name!");
|
||||
AddStep(@"change availability", () => Room.Availability.Value = RoomAvailability.InviteOnly);
|
||||
AddStep(@"change status", () => Room.Status.Value = new RoomStatusOpen());
|
||||
AddStep(@"null beatmap", () => Room.Playlist.Clear());
|
||||
AddStep(@"change beatmap", () =>
|
||||
{
|
||||
Room.Playlist.Clear();
|
||||
Room.Playlist.Add(new PlaylistItem
|
||||
{
|
||||
Beatmap =
|
||||
{
|
||||
Value = new BeatmapInfo
|
||||
{
|
||||
StarDifficulty = 4.2,
|
||||
Ruleset = rulesets.GetRuleset(3),
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Title = @"Your Song",
|
||||
Artist = @"Tester",
|
||||
AuthorString = @"Someone",
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
// 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 osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Screens.Multi.Match.Components;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
public class TestSceneMatchLeaderboardChatDisplay : MultiplayerTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(LeaderboardChatDisplay)
|
||||
};
|
||||
|
||||
protected override bool UseOnlineAPI => true;
|
||||
|
||||
public TestSceneMatchLeaderboardChatDisplay()
|
||||
{
|
||||
Room.RoomID.Value = 7;
|
||||
|
||||
Add(new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(500),
|
||||
Child = new LeaderboardChatDisplay
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,52 +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 NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Screens.Multi.Match.Components;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneMatchParticipants : MultiplayerTestScene
|
||||
{
|
||||
public TestSceneMatchParticipants()
|
||||
{
|
||||
Add(new Participants { RelativeSizeAxes = Axes.Both });
|
||||
|
||||
AddStep(@"set max to null", () => Room.MaxParticipants.Value = null);
|
||||
AddStep(@"set users", () => Room.Participants.AddRange(new[]
|
||||
{
|
||||
new User
|
||||
{
|
||||
Username = @"Feppla",
|
||||
Id = 4271601,
|
||||
Country = new Country { FlagName = @"SE" },
|
||||
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c2.jpg",
|
||||
IsSupporter = true,
|
||||
},
|
||||
new User
|
||||
{
|
||||
Username = @"Xilver",
|
||||
Id = 3099689,
|
||||
Country = new Country { FlagName = @"IL" },
|
||||
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c2.jpg",
|
||||
IsSupporter = true,
|
||||
},
|
||||
new User
|
||||
{
|
||||
Username = @"Wucki",
|
||||
Id = 5287410,
|
||||
Country = new Country { FlagName = @"FI" },
|
||||
CoverUrl = @"https://assets.ppy.sh/user-profile-covers/5287410/5cfeaa9dd41cbce038ecdc9d781396ed4b0108089170bf7f50492ef8eadeb368.jpeg",
|
||||
IsSupporter = true,
|
||||
},
|
||||
}));
|
||||
|
||||
AddStep(@"set max", () => Room.MaxParticipants.Value = 10);
|
||||
AddStep(@"clear users", () => Room.Participants.Clear());
|
||||
AddStep(@"set max to null", () => Room.MaxParticipants.Value = null);
|
||||
}
|
||||
}
|
||||
}
|
158
osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSongSelect.cs
Normal file
@ -0,0 +1,158 @@
|
||||
// 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.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Screens.Multi.Components;
|
||||
using osu.Game.Screens.Select;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
public class TestSceneMatchSongSelect : MultiplayerTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(MatchSongSelect),
|
||||
typeof(MatchBeatmapDetailArea),
|
||||
};
|
||||
|
||||
[Resolved]
|
||||
private BeatmapManager beatmapManager { get; set; }
|
||||
|
||||
private BeatmapManager manager;
|
||||
|
||||
private RulesetStore rulesets;
|
||||
|
||||
private TestMatchSongSelect songSelect;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(GameHost host, AudioManager audio)
|
||||
{
|
||||
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
|
||||
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default));
|
||||
|
||||
var beatmaps = new List<BeatmapInfo>();
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
int beatmapId = 10 * 10 + i;
|
||||
|
||||
int length = RNG.Next(30000, 200000);
|
||||
double bpm = RNG.NextSingle(80, 200);
|
||||
|
||||
beatmaps.Add(new BeatmapInfo
|
||||
{
|
||||
Ruleset = new OsuRuleset().RulesetInfo,
|
||||
OnlineBeatmapID = beatmapId,
|
||||
Path = "normal.osu",
|
||||
Version = $"{beatmapId} (length {TimeSpan.FromMilliseconds(length):m\\:ss}, bpm {bpm:0.#})",
|
||||
Length = length,
|
||||
BPM = bpm,
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
OverallDifficulty = 3.5f,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
manager.Import(new BeatmapSetInfo
|
||||
{
|
||||
OnlineBeatmapSetID = 10,
|
||||
Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(),
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
// Create random metadata, then we can check if sorting works based on these
|
||||
Artist = "Some Artist " + RNG.Next(0, 9),
|
||||
Title = $"Some Song (set id 10), max bpm {beatmaps.Max(b => b.BPM):0.#})",
|
||||
AuthorString = "Some Guy " + RNG.Next(0, 9),
|
||||
},
|
||||
Beatmaps = beatmaps,
|
||||
DateAdded = DateTimeOffset.UtcNow,
|
||||
}).Wait();
|
||||
}
|
||||
|
||||
public override void SetUpSteps()
|
||||
{
|
||||
base.SetUpSteps();
|
||||
|
||||
AddStep("reset", () =>
|
||||
{
|
||||
Ruleset.Value = new OsuRuleset().RulesetInfo;
|
||||
Beatmap.SetDefault();
|
||||
});
|
||||
|
||||
AddStep("create song select", () => LoadScreen(songSelect = new TestMatchSongSelect()));
|
||||
AddUntilStep("wait for present", () => songSelect.IsCurrentScreen());
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public void Setup() => Schedule(() =>
|
||||
{
|
||||
Room.Playlist.Clear();
|
||||
});
|
||||
|
||||
[Test]
|
||||
public void TestItemAddedIfEmptyOnStart()
|
||||
{
|
||||
AddStep("finalise selection", () => songSelect.FinaliseSelection());
|
||||
AddAssert("playlist has 1 item", () => Room.Playlist.Count == 1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestItemAddedWhenCreateNewItemClicked()
|
||||
{
|
||||
AddStep("create new item", () => songSelect.BeatmapDetails.CreateNewItem());
|
||||
AddAssert("playlist has 1 item", () => Room.Playlist.Count == 1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestItemNotAddedIfExistingOnStart()
|
||||
{
|
||||
AddStep("create new item", () => songSelect.BeatmapDetails.CreateNewItem());
|
||||
AddStep("finalise selection", () => songSelect.FinaliseSelection());
|
||||
AddAssert("playlist has 1 item", () => Room.Playlist.Count == 1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAddSameItemMultipleTimes()
|
||||
{
|
||||
AddStep("create new item", () => songSelect.BeatmapDetails.CreateNewItem());
|
||||
AddStep("create new item", () => songSelect.BeatmapDetails.CreateNewItem());
|
||||
AddAssert("playlist has 2 items", () => Room.Playlist.Count == 2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAddItemAfterRearrangement()
|
||||
{
|
||||
AddStep("create new item", () => songSelect.BeatmapDetails.CreateNewItem());
|
||||
AddStep("create new item", () => songSelect.BeatmapDetails.CreateNewItem());
|
||||
AddStep("rearrange", () =>
|
||||
{
|
||||
var item = Room.Playlist[0];
|
||||
Room.Playlist.RemoveAt(0);
|
||||
Room.Playlist.Add(item);
|
||||
});
|
||||
|
||||
AddStep("create new item", () => songSelect.BeatmapDetails.CreateNewItem());
|
||||
AddAssert("new item has id 2", () => Room.Playlist.Last().ID == 2);
|
||||
}
|
||||
|
||||
private class TestMatchSongSelect : MatchSongSelect
|
||||
{
|
||||
public new MatchBeatmapDetailArea BeatmapDetails => (MatchBeatmapDetailArea)base.BeatmapDetails;
|
||||
}
|
||||
}
|
||||
}
|
121
osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSubScreen.cs
Normal 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Screens.Multi;
|
||||
using osu.Game.Screens.Multi.Match;
|
||||
using osu.Game.Screens.Multi.Match.Components;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
using osu.Game.Users;
|
||||
using osuTK.Input;
|
||||
using Header = osu.Game.Screens.Multi.Match.Components.Header;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
public class TestSceneMatchSubScreen : MultiplayerTestScene
|
||||
{
|
||||
protected override bool UseOnlineAPI => true;
|
||||
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(Screens.Multi.Multiplayer),
|
||||
typeof(MatchSubScreen),
|
||||
typeof(Header),
|
||||
typeof(Footer)
|
||||
};
|
||||
|
||||
[Cached(typeof(IRoomManager))]
|
||||
private readonly TestRoomManager roomManager = new TestRoomManager();
|
||||
|
||||
[Resolved]
|
||||
private BeatmapManager beatmaps { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private RulesetStore rulesets { get; set; }
|
||||
|
||||
private TestMatchSubScreen match;
|
||||
|
||||
[SetUp]
|
||||
public void Setup() => Schedule(() =>
|
||||
{
|
||||
Room.CopyFrom(new Room());
|
||||
});
|
||||
|
||||
[SetUpSteps]
|
||||
public void SetupSteps()
|
||||
{
|
||||
AddStep("load match", () => LoadScreen(match = new TestMatchSubScreen(Room)));
|
||||
AddUntilStep("wait for load", () => match.IsCurrentScreen());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestPlaylistItemSelectedOnCreate()
|
||||
{
|
||||
AddStep("set room properties", () =>
|
||||
{
|
||||
Room.Name.Value = "my awesome room";
|
||||
Room.Host.Value = new User { Id = 2, Username = "peppy" };
|
||||
Room.Playlist.Add(new PlaylistItem
|
||||
{
|
||||
Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo },
|
||||
Ruleset = { Value = new OsuRuleset().RulesetInfo }
|
||||
});
|
||||
});
|
||||
|
||||
AddStep("move mouse to create button", () =>
|
||||
{
|
||||
var footer = match.ChildrenOfType<Footer>().Single();
|
||||
InputManager.MoveMouseTo(footer.ChildrenOfType<OsuButton>().Single());
|
||||
});
|
||||
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
|
||||
AddAssert("first playlist item selected", () => match.SelectedItem.Value == Room.Playlist[0]);
|
||||
}
|
||||
|
||||
private class TestMatchSubScreen : MatchSubScreen
|
||||
{
|
||||
public new Bindable<PlaylistItem> SelectedItem => base.SelectedItem;
|
||||
|
||||
public TestMatchSubScreen(Room room)
|
||||
: base(room)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private class TestRoomManager : IRoomManager
|
||||
{
|
||||
public event Action RoomsUpdated
|
||||
{
|
||||
add => throw new NotImplementedException();
|
||||
remove => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IBindableList<Room> Rooms { get; } = new BindableList<Room>();
|
||||
|
||||
public void CreateRoom(Room room, Action<Room> onSuccess = null, Action<string> onError = null)
|
||||
{
|
||||
room.RoomID.Value = 1;
|
||||
onSuccess?.Invoke(room);
|
||||
}
|
||||
|
||||
public void JoinRoom(Room room, Action<Room> onSuccess = null, Action<string> onError = null) => onSuccess?.Invoke(room);
|
||||
|
||||
public void PartRoom()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
// 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.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Screens.Multi.Match.Components;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
public class TestSceneOverlinedParticipants : MultiplayerTestScene
|
||||
{
|
||||
protected override bool UseOnlineAPI => true;
|
||||
|
||||
public TestSceneOverlinedParticipants()
|
||||
{
|
||||
Room.RoomID.Value = 7;
|
||||
|
||||
Add(new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(500),
|
||||
Child = new OverlinedParticipants()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
// 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.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Screens.Multi.Match.Components;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
public class TestSceneOverlinedPlaylist : MultiplayerTestScene
|
||||
{
|
||||
protected override bool UseOnlineAPI => true;
|
||||
|
||||
public TestSceneOverlinedPlaylist()
|
||||
{
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
Room.Playlist.Add(new PlaylistItem
|
||||
{
|
||||
ID = i,
|
||||
Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo },
|
||||
Ruleset = { Value = new OsuRuleset().RulesetInfo }
|
||||
});
|
||||
}
|
||||
|
||||
Add(new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(500),
|
||||
Child = new OverlinedPlaylist(false)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
// 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.Graphics;
|
||||
using osu.Game.Screens.Multi.Components;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
public class TestSceneParticipantsList : MultiplayerTestScene
|
||||
{
|
||||
protected override bool UseOnlineAPI => true;
|
||||
|
||||
public TestSceneParticipantsList()
|
||||
{
|
||||
Room.RoomID.Value = 7;
|
||||
|
||||
Add(new ParticipantsList { RelativeSizeAxes = Axes.Both });
|
||||
}
|
||||
}
|
||||
}
|
@ -117,6 +117,8 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
{
|
||||
base.LoadComplete();
|
||||
API.Login("Rhythm Champion", "osu!");
|
||||
|
||||
Dependencies.Get<SessionStatics>().Set(Static.MutedAudioNotificationShownOnce, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
typeof(CommentsHeader),
|
||||
typeof(DrawableComment),
|
||||
typeof(HeaderButton),
|
||||
typeof(SortTabControl),
|
||||
typeof(OverlaySortTabControl<>),
|
||||
typeof(ShowChildrenButton),
|
||||
typeof(DeletedCommentsCounter),
|
||||
typeof(VotePill),
|
||||
|
@ -18,7 +18,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
typeof(CommentsHeader),
|
||||
typeof(HeaderButton),
|
||||
typeof(SortTabControl),
|
||||
typeof(OverlaySortTabControl<>),
|
||||
};
|
||||
|
||||
[Cached]
|
||||
|
@ -4,6 +4,8 @@
|
||||
using osu.Game.Overlays.BeatmapSet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Mania;
|
||||
@ -15,6 +17,7 @@ using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
@ -44,27 +47,31 @@ namespace osu.Game.Tests.Visual.Online
|
||||
Ruleset = { BindTarget = ruleset }
|
||||
});
|
||||
|
||||
modSelector.SelectedMods.ItemsAdded += mods =>
|
||||
modSelector.SelectedMods.CollectionChanged += (_, args) =>
|
||||
{
|
||||
mods.ForEach(mod => selectedMods.Add(new OsuSpriteText
|
||||
switch (args.Action)
|
||||
{
|
||||
Text = mod.Acronym,
|
||||
}));
|
||||
};
|
||||
|
||||
modSelector.SelectedMods.ItemsRemoved += mods =>
|
||||
{
|
||||
mods.ForEach(mod =>
|
||||
{
|
||||
foreach (var selected in selectedMods)
|
||||
{
|
||||
if (selected.Text == mod.Acronym)
|
||||
case NotifyCollectionChangedAction.Add:
|
||||
args.NewItems.Cast<Mod>().ForEach(mod => selectedMods.Add(new OsuSpriteText
|
||||
{
|
||||
selectedMods.Remove(selected);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
Text = mod.Acronym,
|
||||
}));
|
||||
break;
|
||||
|
||||
case NotifyCollectionChangedAction.Remove:
|
||||
args.OldItems.Cast<Mod>().ForEach(mod =>
|
||||
{
|
||||
foreach (var selected in selectedMods)
|
||||
{
|
||||
if (selected.Text == mod.Acronym)
|
||||
{
|
||||
selectedMods.Remove(selected);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
AddStep("osu ruleset", () => ruleset.Value = new OsuRuleset().RulesetInfo);
|
||||
|
@ -4,8 +4,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Profile.Sections;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
@ -17,6 +19,9 @@ namespace osu.Game.Tests.Visual.Online
|
||||
typeof(CounterPill)
|
||||
};
|
||||
|
||||
[Cached]
|
||||
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Red);
|
||||
|
||||
private readonly CounterPill pill;
|
||||
private readonly BindableInt value = new BindableInt();
|
||||
|
||||
|
@ -128,17 +128,17 @@ namespace osu.Game.Tests.Visual.Online
|
||||
|
||||
const int messages_per_call = 10;
|
||||
AddRepeatStep("add many messages", () =>
|
||||
{
|
||||
for (int i = 0; i < messages_per_call; i++)
|
||||
{
|
||||
for (int i = 0; i < messages_per_call; i++)
|
||||
testChannel.AddNewMessages(new Message(sequence++)
|
||||
{
|
||||
testChannel.AddNewMessages(new Message(sequence++)
|
||||
{
|
||||
Sender = longUsernameUser,
|
||||
Content = "Many messages! " + Guid.NewGuid(),
|
||||
Timestamp = DateTimeOffset.Now
|
||||
});
|
||||
}
|
||||
}, Channel.MAX_HISTORY / messages_per_call + 5);
|
||||
Sender = longUsernameUser,
|
||||
Content = "Many messages! " + Guid.NewGuid(),
|
||||
Timestamp = DateTimeOffset.Now
|
||||
});
|
||||
}
|
||||
}, Channel.MAX_HISTORY / messages_per_call + 5);
|
||||
|
||||
AddAssert("Ensure no adjacent day separators", () =>
|
||||
{
|
||||
|
@ -28,7 +28,30 @@ namespace osu.Game.Tests.Visual.Online
|
||||
|
||||
public TestSceneUserProfileScores()
|
||||
{
|
||||
var score = new ScoreInfo
|
||||
var firstScore = new ScoreInfo
|
||||
{
|
||||
PP = 1047.21,
|
||||
Rank = ScoreRank.SH,
|
||||
Beatmap = new BeatmapInfo
|
||||
{
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Title = "JUSTadICE (TV Size)",
|
||||
Artist = "Oomori Seiko"
|
||||
},
|
||||
Version = "Extreme"
|
||||
},
|
||||
Date = DateTimeOffset.Now,
|
||||
Mods = new Mod[]
|
||||
{
|
||||
new OsuModHidden(),
|
||||
new OsuModHardRock(),
|
||||
new OsuModDoubleTime()
|
||||
},
|
||||
Accuracy = 0.9813
|
||||
};
|
||||
|
||||
var secondScore = new ScoreInfo
|
||||
{
|
||||
PP = 134.32,
|
||||
Rank = ScoreRank.A,
|
||||
@ -50,6 +73,23 @@ namespace osu.Game.Tests.Visual.Online
|
||||
Accuracy = 0.998546
|
||||
};
|
||||
|
||||
var thirdScore = new ScoreInfo
|
||||
{
|
||||
PP = 96.83,
|
||||
Rank = ScoreRank.S,
|
||||
Beatmap = new BeatmapInfo
|
||||
{
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Title = "Idolize",
|
||||
Artist = "Creo"
|
||||
},
|
||||
Version = "Insane"
|
||||
},
|
||||
Date = DateTimeOffset.Now,
|
||||
Accuracy = 0.9726
|
||||
};
|
||||
|
||||
var noPPScore = new ScoreInfo
|
||||
{
|
||||
Rank = ScoreRank.B,
|
||||
@ -76,9 +116,12 @@ namespace osu.Game.Tests.Visual.Online
|
||||
Spacing = new Vector2(0, 10),
|
||||
Children = new[]
|
||||
{
|
||||
new ColourProvidedContainer(OverlayColourScheme.Green, new DrawableProfileScore(score)),
|
||||
new ColourProvidedContainer(OverlayColourScheme.Green, new DrawableProfileScore(firstScore)),
|
||||
new ColourProvidedContainer(OverlayColourScheme.Green, new DrawableProfileScore(secondScore)),
|
||||
new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileScore(noPPScore)),
|
||||
new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileWeightedScore(score, 0.85))
|
||||
new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileWeightedScore(firstScore, 0.97)),
|
||||
new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileWeightedScore(secondScore, 0.85)),
|
||||
new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileWeightedScore(thirdScore, 0.66)),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -0,0 +1,55 @@
|
||||
// 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 osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.BeatmapListing;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
public class TestSceneBeatmapListingSort : OsuTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(BeatmapListingSortTabControl),
|
||||
typeof(OverlaySortTabControl<>),
|
||||
};
|
||||
|
||||
[Cached]
|
||||
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
|
||||
|
||||
public TestSceneBeatmapListingSort()
|
||||
{
|
||||
BeatmapListingSortTabControl control;
|
||||
OsuSpriteText current;
|
||||
OsuSpriteText direction;
|
||||
|
||||
Add(control = new BeatmapListingSortTabControl
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
});
|
||||
|
||||
Add(new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(0, 5),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
current = new OsuSpriteText(),
|
||||
direction = new OsuSpriteText()
|
||||
}
|
||||
});
|
||||
|
||||
control.SortDirection.BindValueChanged(sortDirection => direction.Text = $"Sort direction: {sortDirection.NewValue}", true);
|
||||
control.Current.BindValueChanged(criteria => current.Text = $"Criteria: {criteria.NewValue}", true);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.BeatmapListing;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
public class TestSceneBeatmapSearchFilter : OsuTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(BeatmapSearchFilterRow<>),
|
||||
typeof(BeatmapSearchRulesetFilterRow),
|
||||
typeof(BeatmapSearchSmallFilterRow<>),
|
||||
};
|
||||
|
||||
[Cached]
|
||||
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
|
||||
|
||||
private readonly ReverseChildIDFillFlowContainer<Drawable> resizableContainer;
|
||||
|
||||
public TestSceneBeatmapSearchFilter()
|
||||
{
|
||||
Add(resizableContainer = new ReverseChildIDFillFlowContainer<Drawable>
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(0, 10),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new BeatmapSearchRulesetFilterRow(),
|
||||
new BeatmapSearchFilterRow<BeatmapSearchCategory>("Categories"),
|
||||
new BeatmapSearchSmallFilterRow<BeatmapSearchCategory>("Header Name")
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestResize()
|
||||
{
|
||||
AddStep("Resize to 0.3", () => resizableContainer.ResizeWidthTo(0.3f, 1000));
|
||||
AddStep("Resize to 1", () => resizableContainer.ResizeWidthTo(1, 1000));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
// 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.Specialized;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
@ -71,8 +73,19 @@ namespace osu.Game.Tournament.Screens.Editors
|
||||
}
|
||||
});
|
||||
|
||||
Storage.ItemsAdded += items => items.ForEach(i => flow.Add(CreateDrawable(i)));
|
||||
Storage.ItemsRemoved += items => items.ForEach(i => flow.RemoveAll(d => d.Model == i));
|
||||
Storage.CollectionChanged += (_, args) =>
|
||||
{
|
||||
switch (args.Action)
|
||||
{
|
||||
case NotifyCollectionChangedAction.Add:
|
||||
args.NewItems.Cast<TModel>().ForEach(i => flow.Add(CreateDrawable(i)));
|
||||
break;
|
||||
|
||||
case NotifyCollectionChangedAction.Remove:
|
||||
args.OldItems.Cast<TModel>().ForEach(i => flow.RemoveAll(d => d.Model == i));
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
foreach (var model in Storage)
|
||||
flow.Add(CreateDrawable(model));
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
@ -90,8 +91,19 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
|
||||
foreach (var r in rounds.Prepend(new TournamentRound()))
|
||||
add(r);
|
||||
|
||||
rounds.ItemsRemoved += items => items.ForEach(i => Control.RemoveDropdownItem(i));
|
||||
rounds.ItemsAdded += items => items.ForEach(add);
|
||||
rounds.CollectionChanged += (_, args) =>
|
||||
{
|
||||
switch (args.Action)
|
||||
{
|
||||
case NotifyCollectionChangedAction.Add:
|
||||
args.NewItems.Cast<TournamentRound>().ForEach(add);
|
||||
break;
|
||||
|
||||
case NotifyCollectionChangedAction.Remove:
|
||||
args.OldItems.Cast<TournamentRound>().ForEach(i => Control.RemoveDropdownItem(i));
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private readonly List<IUnbindable> refBindables = new List<IUnbindable>();
|
||||
@ -122,8 +134,19 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
|
||||
foreach (var t in teams.Prepend(new TournamentTeam()))
|
||||
add(t);
|
||||
|
||||
teams.ItemsRemoved += items => items.ForEach(i => Control.RemoveDropdownItem(i));
|
||||
teams.ItemsAdded += items => items.ForEach(add);
|
||||
teams.CollectionChanged += (_, args) =>
|
||||
{
|
||||
switch (args.Action)
|
||||
{
|
||||
case NotifyCollectionChangedAction.Add:
|
||||
args.NewItems.Cast<TournamentTeam>().ForEach(add);
|
||||
break;
|
||||
|
||||
case NotifyCollectionChangedAction.Remove:
|
||||
args.OldItems.Cast<TournamentTeam>().ForEach(i => Control.RemoveDropdownItem(i));
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private readonly List<IUnbindable> refBindables = new List<IUnbindable>();
|
||||
|
@ -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.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Caching;
|
||||
@ -68,22 +69,24 @@ namespace osu.Game.Tournament.Screens.Ladder
|
||||
foreach (var match in LadderInfo.Matches)
|
||||
addMatch(match);
|
||||
|
||||
LadderInfo.Rounds.ItemsAdded += _ => layout.Invalidate();
|
||||
LadderInfo.Rounds.ItemsRemoved += _ => layout.Invalidate();
|
||||
|
||||
LadderInfo.Matches.ItemsAdded += matches =>
|
||||
LadderInfo.Rounds.CollectionChanged += (_, __) => layout.Invalidate();
|
||||
LadderInfo.Matches.CollectionChanged += (_, args) =>
|
||||
{
|
||||
foreach (var p in matches)
|
||||
addMatch(p);
|
||||
layout.Invalidate();
|
||||
};
|
||||
|
||||
LadderInfo.Matches.ItemsRemoved += matches =>
|
||||
{
|
||||
foreach (var p in matches)
|
||||
switch (args.Action)
|
||||
{
|
||||
foreach (var d in MatchesContainer.Where(d => d.Match == p))
|
||||
d.Expire();
|
||||
case NotifyCollectionChangedAction.Add:
|
||||
foreach (var p in args.NewItems.Cast<TournamentMatch>())
|
||||
addMatch(p);
|
||||
break;
|
||||
|
||||
case NotifyCollectionChangedAction.Remove:
|
||||
foreach (var p in args.NewItems.Cast<TournamentMatch>())
|
||||
{
|
||||
foreach (var d in MatchesContainer.Where(d => d.Match == p))
|
||||
d.Expire();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
layout.Invalidate();
|
||||
|
@ -19,13 +19,15 @@ namespace osu.Game.Audio
|
||||
{
|
||||
private readonly BindableDouble muteBindable = new BindableDouble();
|
||||
|
||||
private AudioManager audio;
|
||||
[Resolved]
|
||||
private AudioManager audio { get; set; }
|
||||
|
||||
private PreviewTrackStore trackStore;
|
||||
|
||||
protected TrackManagerPreviewTrack CurrentTrack;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio)
|
||||
private void load()
|
||||
{
|
||||
// this is a temporary solution to get around muting ourselves.
|
||||
// todo: update this once we have a BackgroundTrackManager or similar.
|
||||
@ -33,8 +35,6 @@ namespace osu.Game.Audio
|
||||
|
||||
audio.AddItem(trackStore);
|
||||
trackStore.AddAdjustment(AdjustableProperty.Volume, audio.VolumeTrack);
|
||||
|
||||
this.audio = audio;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -90,6 +90,7 @@ namespace osu.Game.Audio
|
||||
|
||||
public class TrackManagerPreviewTrack : PreviewTrack
|
||||
{
|
||||
[Resolved]
|
||||
public IPreviewTrackOwner Owner { get; private set; }
|
||||
|
||||
private readonly BeatmapSetInfo beatmapSetInfo;
|
||||
@ -101,12 +102,6 @@ namespace osu.Game.Audio
|
||||
this.trackManager = trackManager;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(IPreviewTrackOwner owner)
|
||||
{
|
||||
Owner = owner;
|
||||
}
|
||||
|
||||
protected override Track GetTrack() => trackManager.Get($"https://b.ppy.sh/preview/{beatmapSetInfo?.OnlineBeatmapSetID}.mp3");
|
||||
}
|
||||
|
||||
|
@ -74,7 +74,9 @@ namespace osu.Game.Beatmaps
|
||||
|
||||
try
|
||||
{
|
||||
return new VideoSprite(textureStore.GetStream(getPathForFile(Metadata.VideoFile)));
|
||||
var stream = textureStore.GetStream(getPathForFile(Metadata.VideoFile));
|
||||
|
||||
return stream == null ? null : new VideoSprite(stream);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -150,12 +150,12 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
};
|
||||
}
|
||||
|
||||
private OsuColour colours;
|
||||
[Resolved]
|
||||
private OsuColour colours { get; set; }
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
private void load()
|
||||
{
|
||||
this.colours = colours;
|
||||
background.Colour = colours.Gray3;
|
||||
}
|
||||
|
||||
|
@ -105,9 +105,10 @@ namespace osu.Game.Database
|
||||
|
||||
void triggerFailure(Exception error)
|
||||
{
|
||||
currentDownloads.Remove(request);
|
||||
|
||||
DownloadFailed?.Invoke(request);
|
||||
|
||||
currentDownloads.Remove(request);
|
||||
notification.State = ProgressNotificationState.Cancelled;
|
||||
|
||||
if (!(error is OperationCanceledException))
|
||||
|
@ -0,0 +1,26 @@
|
||||
// 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.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
|
||||
namespace osu.Game.Graphics.Containers
|
||||
{
|
||||
public abstract class OsuRearrangeableListContainer<TModel> : RearrangeableListContainer<TModel>
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether any item is currently being dragged. Used to hide other items' drag handles.
|
||||
/// </summary>
|
||||
private readonly BindableBool playlistDragActive = new BindableBool();
|
||||
|
||||
protected override ScrollContainer<Drawable> CreateScrollContainer() => new OsuScrollContainer();
|
||||
|
||||
protected sealed override RearrangeableListItem<TModel> CreateDrawable(TModel item) => CreateOsuDrawable(item).With(d =>
|
||||
{
|
||||
d.PlaylistDragActive.BindTo(playlistDragActive);
|
||||
});
|
||||
|
||||
protected abstract OsuRearrangeableListItem<TModel> CreateOsuDrawable(TModel item);
|
||||
}
|
||||
}
|
162
osu.Game/Graphics/Containers/OsuRearrangeableListItem.cs
Normal file
@ -0,0 +1,162 @@
|
||||
// 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.Sprites;
|
||||
using osu.Framework.Input.Events;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Graphics.Containers
|
||||
{
|
||||
public abstract class OsuRearrangeableListItem<TModel> : RearrangeableListItem<TModel>
|
||||
{
|
||||
public const float FADE_DURATION = 100;
|
||||
|
||||
/// <summary>
|
||||
/// Whether any item is currently being dragged. Used to hide other items' drag handles.
|
||||
/// </summary>
|
||||
public readonly BindableBool PlaylistDragActive = new BindableBool();
|
||||
|
||||
private Color4 handleColour = Color4.White;
|
||||
|
||||
/// <summary>
|
||||
/// The colour of the drag handle.
|
||||
/// </summary>
|
||||
protected Color4 HandleColour
|
||||
{
|
||||
get => handleColour;
|
||||
set
|
||||
{
|
||||
if (handleColour == value)
|
||||
return;
|
||||
|
||||
handleColour = value;
|
||||
|
||||
if (handle != null)
|
||||
handle.Colour = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the drag handle should be shown.
|
||||
/// </summary>
|
||||
protected virtual bool ShowDragHandle => true;
|
||||
|
||||
private PlaylistItemHandle handle;
|
||||
|
||||
protected OsuRearrangeableListItem(TModel item)
|
||||
: base(item)
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Container handleContainer;
|
||||
|
||||
InternalChild = new GridContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Content = new[]
|
||||
{
|
||||
new[]
|
||||
{
|
||||
handleContainer = new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Horizontal = 5 },
|
||||
Child = handle = new PlaylistItemHandle
|
||||
{
|
||||
Size = new Vector2(12),
|
||||
Colour = HandleColour,
|
||||
AlwaysPresent = true,
|
||||
Alpha = 0
|
||||
}
|
||||
},
|
||||
CreateContent()
|
||||
}
|
||||
},
|
||||
ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize) },
|
||||
RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }
|
||||
};
|
||||
|
||||
if (!ShowDragHandle)
|
||||
handleContainer.Alpha = 0;
|
||||
}
|
||||
|
||||
protected override bool OnDragStart(DragStartEvent e)
|
||||
{
|
||||
if (!base.OnDragStart(e))
|
||||
return false;
|
||||
|
||||
PlaylistDragActive.Value = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnDragEnd(DragEndEvent e)
|
||||
{
|
||||
PlaylistDragActive.Value = false;
|
||||
base.OnDragEnd(e);
|
||||
}
|
||||
|
||||
protected override bool IsDraggableAt(Vector2 screenSpacePos) => handle.HandlingDrag;
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
handle.UpdateHoverState(IsDragged || !PlaylistDragActive.Value);
|
||||
return base.OnHover(e);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e) => handle.UpdateHoverState(false);
|
||||
|
||||
protected abstract Drawable CreateContent();
|
||||
|
||||
public class PlaylistItemHandle : SpriteIcon
|
||||
{
|
||||
public bool HandlingDrag { get; private set; }
|
||||
private bool isHovering;
|
||||
|
||||
public PlaylistItemHandle()
|
||||
{
|
||||
Icon = FontAwesome.Solid.Bars;
|
||||
}
|
||||
|
||||
protected override bool OnMouseDown(MouseDownEvent e)
|
||||
{
|
||||
base.OnMouseDown(e);
|
||||
|
||||
HandlingDrag = true;
|
||||
UpdateHoverState(isHovering);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override void OnMouseUp(MouseUpEvent e)
|
||||
{
|
||||
base.OnMouseUp(e);
|
||||
|
||||
HandlingDrag = false;
|
||||
UpdateHoverState(isHovering);
|
||||
}
|
||||
|
||||
public void UpdateHoverState(bool hovering)
|
||||
{
|
||||
isHovering = hovering;
|
||||
|
||||
if (isHovering || HandlingDrag)
|
||||
this.FadeIn(FADE_DURATION);
|
||||
else
|
||||
this.FadeOut(FADE_DURATION);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -35,18 +35,20 @@ namespace osu.Game.Graphics
|
||||
private Bindable<ScreenshotFormat> screenshotFormat;
|
||||
private Bindable<bool> captureMenuCursor;
|
||||
|
||||
private GameHost host;
|
||||
[Resolved]
|
||||
private GameHost host { get; set; }
|
||||
|
||||
private Storage storage;
|
||||
private NotificationOverlay notificationOverlay;
|
||||
|
||||
[Resolved]
|
||||
private NotificationOverlay notificationOverlay { get; set; }
|
||||
|
||||
private SampleChannel shutter;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(GameHost host, OsuConfigManager config, Storage storage, NotificationOverlay notificationOverlay, AudioManager audio)
|
||||
private void load(OsuConfigManager config, Storage storage, AudioManager audio)
|
||||
{
|
||||
this.host = host;
|
||||
this.storage = storage.GetStorageForDirectory(@"screenshots");
|
||||
this.notificationOverlay = notificationOverlay;
|
||||
|
||||
screenshotFormat = config.GetBindable<ScreenshotFormat>(OsuSetting.ScreenshotFormat);
|
||||
captureMenuCursor = config.GetBindable<bool>(OsuSetting.ScreenshotCaptureMenuCursor);
|
||||
|
@ -19,7 +19,8 @@ namespace osu.Game.Graphics.UserInterface
|
||||
private readonly SpriteIcon checkmark;
|
||||
private readonly Box background;
|
||||
|
||||
private OsuColour colours;
|
||||
[Resolved]
|
||||
private OsuColour colours { get; set; }
|
||||
|
||||
public DownloadButton()
|
||||
{
|
||||
@ -49,10 +50,8 @@ namespace osu.Game.Graphics.UserInterface
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
private void load()
|
||||
{
|
||||
this.colours = colours;
|
||||
|
||||
State.BindValueChanged(updateState, true);
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,9 @@ namespace osu.Game.Graphics.UserInterface
|
||||
public string Link { get; set; }
|
||||
|
||||
private Color4 hoverColour;
|
||||
private GameHost host;
|
||||
|
||||
[Resolved]
|
||||
private GameHost host { get; set; }
|
||||
|
||||
public ExternalLinkButton(string link = null)
|
||||
{
|
||||
@ -32,10 +34,9 @@ namespace osu.Game.Graphics.UserInterface
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours, GameHost host)
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
hoverColour = colours.Yellow;
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
|
@ -36,13 +36,12 @@ namespace osu.Game.Graphics.UserInterface
|
||||
}
|
||||
}
|
||||
|
||||
private GameHost host;
|
||||
[Resolved]
|
||||
private GameHost host { get; set; }
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(GameHost host)
|
||||
private void load()
|
||||
{
|
||||
this.host = host;
|
||||
|
||||
BackgroundUnfocused = new Color4(10, 10, 10, 255);
|
||||
BackgroundFocused = new Color4(10, 10, 10, 255);
|
||||
}
|
||||
|
@ -24,7 +24,8 @@ namespace osu.Game.Graphics.UserInterface
|
||||
|
||||
private readonly CapsWarning warning;
|
||||
|
||||
private GameHost host;
|
||||
[Resolved]
|
||||
private GameHost host { get; set; }
|
||||
|
||||
public OsuPasswordTextBox()
|
||||
{
|
||||
@ -38,12 +39,6 @@ namespace osu.Game.Graphics.UserInterface
|
||||
});
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(GameHost host)
|
||||
{
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
protected override bool OnKeyDown(KeyDownEvent e)
|
||||
{
|
||||
if (e.Key == Key.CapsLock)
|
||||
|
@ -39,7 +39,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
|
||||
private readonly Box strip;
|
||||
|
||||
protected override Dropdown<T> CreateDropdown() => new OsuTabDropdown();
|
||||
protected override Dropdown<T> CreateDropdown() => new OsuTabDropdown<T>();
|
||||
|
||||
protected override TabItem<T> CreateTabItem(T value) => new OsuTabItem(value);
|
||||
|
||||
@ -180,100 +180,5 @@ namespace osu.Game.Graphics.UserInterface
|
||||
|
||||
protected override void OnDeactivated() => fadeInactive();
|
||||
}
|
||||
|
||||
// todo: this needs to go
|
||||
private class OsuTabDropdown : OsuDropdown<T>
|
||||
{
|
||||
public OsuTabDropdown()
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
}
|
||||
|
||||
protected override DropdownMenu CreateMenu() => new OsuTabDropdownMenu();
|
||||
|
||||
protected override DropdownHeader CreateHeader() => new OsuTabDropdownHeader
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight
|
||||
};
|
||||
|
||||
private class OsuTabDropdownMenu : OsuDropdownMenu
|
||||
{
|
||||
public OsuTabDropdownMenu()
|
||||
{
|
||||
Anchor = Anchor.TopRight;
|
||||
Origin = Anchor.TopRight;
|
||||
|
||||
BackgroundColour = Color4.Black.Opacity(0.7f);
|
||||
MaxHeight = 400;
|
||||
}
|
||||
|
||||
protected override DrawableDropdownMenuItem CreateDrawableDropdownMenuItem(MenuItem item) => new DrawableOsuTabDropdownMenuItem(item) { AccentColour = AccentColour };
|
||||
|
||||
private class DrawableOsuTabDropdownMenuItem : DrawableOsuDropdownMenuItem
|
||||
{
|
||||
public DrawableOsuTabDropdownMenuItem(MenuItem item)
|
||||
: base(item)
|
||||
{
|
||||
ForegroundColourHover = Color4.Black;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected class OsuTabDropdownHeader : OsuDropdownHeader
|
||||
{
|
||||
public override Color4 AccentColour
|
||||
{
|
||||
get => base.AccentColour;
|
||||
set
|
||||
{
|
||||
base.AccentColour = value;
|
||||
Foreground.Colour = value;
|
||||
}
|
||||
}
|
||||
|
||||
public OsuTabDropdownHeader()
|
||||
{
|
||||
RelativeSizeAxes = Axes.None;
|
||||
AutoSizeAxes = Axes.X;
|
||||
|
||||
BackgroundColour = Color4.Black.Opacity(0.5f);
|
||||
|
||||
Background.Height = 0.5f;
|
||||
Background.CornerRadius = 5;
|
||||
Background.Masking = true;
|
||||
|
||||
Foreground.RelativeSizeAxes = Axes.None;
|
||||
Foreground.AutoSizeAxes = Axes.X;
|
||||
Foreground.RelativeSizeAxes = Axes.Y;
|
||||
Foreground.Margin = new MarginPadding(5);
|
||||
|
||||
Foreground.Children = new Drawable[]
|
||||
{
|
||||
new SpriteIcon
|
||||
{
|
||||
Icon = FontAwesome.Solid.EllipsisH,
|
||||
Size = new Vector2(14),
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
}
|
||||
};
|
||||
|
||||
Padding = new MarginPadding { Left = 5, Right = 5 };
|
||||
}
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
Foreground.Colour = BackgroundColour;
|
||||
return base.OnHover(e);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e)
|
||||
{
|
||||
Foreground.Colour = BackgroundColourHover;
|
||||
base.OnHoverLost(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|