mirror of
https://github.com/osukey/osukey.git
synced 2025-08-03 14:46:38 +09:00
Merge branch 'master' into improve-beatmap-card-buttons
This commit is contained in:
@ -244,7 +244,10 @@ namespace osu.Game.Tests.Visual.Background
|
||||
public void TestResumeFromPlayer()
|
||||
{
|
||||
performFullSetup();
|
||||
AddStep("Move mouse to Visual Settings", () => InputManager.MoveMouseTo(playerLoader.VisualSettingsPos));
|
||||
AddStep("Move mouse to Visual Settings location", () => InputManager.MoveMouseTo(playerLoader.ScreenSpaceDrawQuad.TopRight
|
||||
+ new Vector2(-playerLoader.VisualSettingsPos.ScreenSpaceDrawQuad.Width,
|
||||
playerLoader.VisualSettingsPos.ScreenSpaceDrawQuad.Height / 2
|
||||
)));
|
||||
AddStep("Resume PlayerLoader", () => player.Restart());
|
||||
AddUntilStep("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied());
|
||||
AddStep("Move mouse to center of screen", () => InputManager.MoveMouseTo(playerLoader.ScreenPos));
|
||||
|
@ -106,6 +106,49 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
assertBeatSnap(16);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestKeyboardNavigation()
|
||||
{
|
||||
pressKey(1);
|
||||
assertBeatSnap(1);
|
||||
assertPreset(BeatDivisorType.Common);
|
||||
|
||||
pressKey(2);
|
||||
assertBeatSnap(2);
|
||||
assertPreset(BeatDivisorType.Common);
|
||||
|
||||
pressKey(3);
|
||||
assertBeatSnap(3);
|
||||
assertPreset(BeatDivisorType.Triplets);
|
||||
|
||||
pressKey(4);
|
||||
assertBeatSnap(4);
|
||||
assertPreset(BeatDivisorType.Common);
|
||||
|
||||
pressKey(5);
|
||||
assertBeatSnap(5);
|
||||
assertPreset(BeatDivisorType.Custom, 5);
|
||||
|
||||
pressKey(6);
|
||||
assertBeatSnap(6);
|
||||
assertPreset(BeatDivisorType.Triplets);
|
||||
|
||||
pressKey(7);
|
||||
assertBeatSnap(7);
|
||||
assertPreset(BeatDivisorType.Custom, 7);
|
||||
|
||||
pressKey(8);
|
||||
assertBeatSnap(8);
|
||||
assertPreset(BeatDivisorType.Common);
|
||||
|
||||
void pressKey(int key) => AddStep($"press shift+{key}", () =>
|
||||
{
|
||||
InputManager.PressKey(Key.ShiftLeft);
|
||||
InputManager.Key(Key.Number0 + key);
|
||||
InputManager.ReleaseKey(Key.ShiftLeft);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBeatPresetNavigation()
|
||||
{
|
||||
|
@ -193,7 +193,7 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
|
||||
IBindable<double> IDistanceSnapProvider.DistanceSpacingMultiplier => DistanceSpacingMultiplier;
|
||||
|
||||
public float GetBeatSnapDistanceAt(HitObject referenceObject) => beat_snap_distance;
|
||||
public float GetBeatSnapDistanceAt(HitObject referenceObject, bool useReferenceSliderVelocity = true) => beat_snap_distance;
|
||||
|
||||
public float DurationToDistance(HitObject referenceObject, double duration) => (float)duration;
|
||||
|
||||
|
32
osu.Game.Tests/Visual/Editing/TestSceneEditorBindings.cs
Normal file
32
osu.Game.Tests/Visual/Editing/TestSceneEditorBindings.cs
Normal file
@ -0,0 +1,32 @@
|
||||
// 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.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Editing
|
||||
{
|
||||
/// <summary>
|
||||
/// Test editor hotkeys at a high level to ensure they all work well together.
|
||||
/// </summary>
|
||||
public class TestSceneEditorBindings : EditorTestScene
|
||||
{
|
||||
protected override Ruleset CreateEditorRuleset() => new OsuRuleset();
|
||||
|
||||
[Test]
|
||||
public void TestBeatDivisorChangeHotkeys()
|
||||
{
|
||||
AddStep("hold shift", () => InputManager.PressKey(Key.LShift));
|
||||
|
||||
AddStep("press 4", () => InputManager.Key(Key.Number4));
|
||||
AddAssert("snap updated to 4", () => EditorBeatmap.BeatmapInfo.BeatDivisor, () => Is.EqualTo(4));
|
||||
|
||||
AddStep("press 6", () => InputManager.Key(Key.Number6));
|
||||
AddAssert("snap updated to 6", () => EditorBeatmap.BeatmapInfo.BeatDivisor, () => Is.EqualTo(6));
|
||||
|
||||
AddStep("release shift", () => InputManager.ReleaseKey(Key.LShift));
|
||||
}
|
||||
}
|
||||
}
|
@ -155,6 +155,20 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
AddUntilStep("composer selection box is visible", () => Editor.ChildrenOfType<HitObjectComposer>().First().ChildrenOfType<EditorSelectionHandler>().First().Alpha > 0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestClone()
|
||||
{
|
||||
var addedObject = new HitCircle { StartTime = 1000 };
|
||||
AddStep("add hitobject", () => EditorBeatmap.Add(addedObject));
|
||||
AddStep("select added object", () => EditorBeatmap.SelectedHitObjects.Add(addedObject));
|
||||
|
||||
AddAssert("is one object", () => EditorBeatmap.HitObjects.Count == 1);
|
||||
AddStep("clone", () => Editor.Clone());
|
||||
AddAssert("is two objects", () => EditorBeatmap.HitObjects.Count == 2);
|
||||
AddStep("clone", () => Editor.Clone());
|
||||
AddAssert("is three objects", () => EditorBeatmap.HitObjects.Count == 3);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCutNothing()
|
||||
{
|
||||
@ -175,5 +189,22 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
AddStep("paste hitobject", () => Editor.Paste());
|
||||
AddAssert("are no objects", () => EditorBeatmap.HitObjects.Count == 0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCloneNothing()
|
||||
{
|
||||
// Add arbitrary object and copy to clipboard.
|
||||
// This is tested to ensure that clone doesn't incorrectly read from the clipboard when no selection is made.
|
||||
var addedObject = new HitCircle { StartTime = 1000 };
|
||||
AddStep("add hitobject", () => EditorBeatmap.Add(addedObject));
|
||||
AddStep("select added object", () => EditorBeatmap.SelectedHitObjects.Add(addedObject));
|
||||
AddStep("copy hitobject", () => Editor.Copy());
|
||||
|
||||
AddStep("deselect all objects", () => EditorBeatmap.SelectedHitObjects.Clear());
|
||||
|
||||
AddAssert("is one object", () => EditorBeatmap.HitObjects.Count == 1);
|
||||
AddStep("clone", () => Editor.Clone());
|
||||
AddAssert("still one object", () => EditorBeatmap.HitObjects.Count == 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,8 +4,10 @@
|
||||
#nullable disable
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Screens.Edit.Components.RadioButtons;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Editing
|
||||
@ -13,6 +15,9 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
[TestFixture]
|
||||
public class TestSceneEditorComposeRadioButtons : OsuTestScene
|
||||
{
|
||||
[Cached]
|
||||
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Aquamarine);
|
||||
|
||||
public TestSceneEditorComposeRadioButtons()
|
||||
{
|
||||
EditorRadioButtonCollection collection;
|
||||
|
@ -148,10 +148,6 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
});
|
||||
|
||||
AddAssert("no circles placed", () => editorBeatmap.HitObjects.Count == 0);
|
||||
|
||||
AddStep("place circle", () => InputManager.Click(MouseButton.Left));
|
||||
|
||||
AddAssert("circle placed", () => editorBeatmap.HitObjects.Count == 1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -165,10 +161,11 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
AddStep("hold alt", () => InputManager.PressKey(Key.LAlt));
|
||||
|
||||
AddStep("scroll mouse 5 steps", () => InputManager.ScrollVerticalBy(5));
|
||||
AddAssert("distance spacing increased by 0.5", () => editorBeatmap.BeatmapInfo.DistanceSpacing == originalSpacing + 0.5);
|
||||
|
||||
AddStep("release alt", () => InputManager.ReleaseKey(Key.LAlt));
|
||||
AddStep("release ctrl", () => InputManager.ReleaseKey(Key.LControl));
|
||||
|
||||
AddAssert("distance spacing increased by 0.5", () => editorBeatmap.BeatmapInfo.DistanceSpacing == originalSpacing + 0.5);
|
||||
}
|
||||
|
||||
public class EditorBeatmapContainer : Container
|
||||
|
@ -55,7 +55,7 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
}
|
||||
}
|
||||
},
|
||||
new MenuCursor()
|
||||
new MenuCursorContainer()
|
||||
};
|
||||
|
||||
scrollContainer.Add(innerBox = new Box
|
||||
|
@ -1,17 +1,17 @@
|
||||
// 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.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.ObjectExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
@ -26,9 +26,9 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
public class TestSceneHUDOverlay : OsuManualInputManagerTestScene
|
||||
{
|
||||
private OsuConfigManager localConfig;
|
||||
private OsuConfigManager localConfig = null!;
|
||||
|
||||
private HUDOverlay hudOverlay;
|
||||
private HUDOverlay hudOverlay = null!;
|
||||
|
||||
[Cached]
|
||||
private ScoreProcessor scoreProcessor = new ScoreProcessor(new OsuRuleset());
|
||||
@ -149,6 +149,41 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddAssert("key counters still hidden", () => !keyCounterFlow.IsPresent);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestHoldForMenuDoesWorkWhenHidden()
|
||||
{
|
||||
bool activated = false;
|
||||
|
||||
HoldForMenuButton getHoldForMenu() => hudOverlay.ChildrenOfType<HoldForMenuButton>().Single();
|
||||
|
||||
createNew();
|
||||
|
||||
AddStep("bind action", () =>
|
||||
{
|
||||
activated = false;
|
||||
|
||||
var holdForMenu = getHoldForMenu();
|
||||
|
||||
holdForMenu.Action += () => activated = true;
|
||||
});
|
||||
|
||||
AddStep("set showhud false", () => hudOverlay.ShowHud.Value = false);
|
||||
AddUntilStep("hidetarget is hidden", () => !hideTarget.IsPresent);
|
||||
|
||||
AddStep("attempt activate", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(getHoldForMenu().OfType<HoldToConfirmContainer>().Single());
|
||||
InputManager.PressButton(MouseButton.Left);
|
||||
});
|
||||
|
||||
AddUntilStep("activated", () => activated);
|
||||
|
||||
AddStep("release mouse button", () =>
|
||||
{
|
||||
InputManager.ReleaseButton(MouseButton.Left);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestInputDoesntWorkWhenHUDHidden()
|
||||
{
|
||||
@ -220,7 +255,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddUntilStep("skinnable components loaded", () => hudOverlay.ChildrenOfType<SkinnableTargetContainer>().Single().ComponentsLoaded);
|
||||
}
|
||||
|
||||
private void createNew(Action<HUDOverlay> action = null)
|
||||
private void createNew(Action<HUDOverlay>? action = null)
|
||||
{
|
||||
AddStep("create overlay", () =>
|
||||
{
|
||||
@ -239,7 +274,9 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
localConfig?.Dispose();
|
||||
if (localConfig.IsNotNull())
|
||||
localConfig.Dispose();
|
||||
|
||||
base.Dispose(isDisposing);
|
||||
}
|
||||
}
|
||||
|
498
osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs
Normal file
498
osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs
Normal file
@ -0,0 +1,498 @@
|
||||
// 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.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Overlays.Settings;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Beatmaps;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
public class TestSceneScoring : OsuTestScene
|
||||
{
|
||||
private GraphContainer graphs = null!;
|
||||
private SettingsSlider<int> sliderMaxCombo = null!;
|
||||
|
||||
private FillFlowContainer legend = null!;
|
||||
|
||||
[Test]
|
||||
public void TestBasic()
|
||||
{
|
||||
AddStep("setup tests", () =>
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new GridContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
RowDimensions = new[]
|
||||
{
|
||||
new Dimension(),
|
||||
new Dimension(GridSizeMode.AutoSize),
|
||||
new Dimension(GridSizeMode.AutoSize),
|
||||
},
|
||||
Content = new[]
|
||||
{
|
||||
new Drawable[]
|
||||
{
|
||||
graphs = new GraphContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
},
|
||||
new Drawable[]
|
||||
{
|
||||
legend = new FillFlowContainer
|
||||
{
|
||||
Padding = new MarginPadding(20),
|
||||
Direction = FillDirection.Full,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
},
|
||||
},
|
||||
new Drawable[]
|
||||
{
|
||||
new FillFlowContainer
|
||||
{
|
||||
Padding = new MarginPadding(20),
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Full,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
sliderMaxCombo = new SettingsSlider<int>
|
||||
{
|
||||
Width = 0.5f,
|
||||
TransferValueOnCommit = true,
|
||||
Current = new BindableInt(1024)
|
||||
{
|
||||
MinValue = 96,
|
||||
MaxValue = 8192,
|
||||
},
|
||||
LabelText = "max combo",
|
||||
},
|
||||
new OsuTextFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.5f,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Text = $"Left click to add miss\nRight click to add OK/{base_ok}"
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
sliderMaxCombo.Current.BindValueChanged(_ => rerun());
|
||||
|
||||
graphs.MissLocations.BindCollectionChanged((_, __) => rerun());
|
||||
graphs.NonPerfectLocations.BindCollectionChanged((_, __) => rerun());
|
||||
|
||||
graphs.MaxCombo.BindTo(sliderMaxCombo.Current);
|
||||
|
||||
rerun();
|
||||
});
|
||||
}
|
||||
|
||||
private const int base_great = 300;
|
||||
private const int base_ok = 100;
|
||||
|
||||
private void rerun()
|
||||
{
|
||||
graphs.Clear();
|
||||
legend.Clear();
|
||||
|
||||
runForProcessor("lazer-standardised", Color4.YellowGreen, new ScoreProcessor(new OsuRuleset()) { Mode = { Value = ScoringMode.Standardised } });
|
||||
runForProcessor("lazer-classic", Color4.MediumPurple, new ScoreProcessor(new OsuRuleset()) { Mode = { Value = ScoringMode.Classic } });
|
||||
|
||||
runScoreV1();
|
||||
runScoreV2();
|
||||
}
|
||||
|
||||
private void runScoreV1()
|
||||
{
|
||||
int totalScore = 0;
|
||||
int currentCombo = 0;
|
||||
|
||||
void applyHitV1(int baseScore)
|
||||
{
|
||||
if (baseScore == 0)
|
||||
{
|
||||
currentCombo = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const float score_multiplier = 1;
|
||||
|
||||
totalScore += baseScore;
|
||||
|
||||
// combo multiplier
|
||||
// ReSharper disable once PossibleLossOfFraction
|
||||
totalScore += (int)(Math.Max(0, currentCombo - 1) * (baseScore / 25 * score_multiplier));
|
||||
|
||||
currentCombo++;
|
||||
}
|
||||
|
||||
runForAlgorithm("ScoreV1 (classic)", Color4.Purple,
|
||||
() => applyHitV1(base_great),
|
||||
() => applyHitV1(base_ok),
|
||||
() => applyHitV1(0),
|
||||
() =>
|
||||
{
|
||||
// Arbitrary value chosen towards the upper range.
|
||||
const double score_multiplier = 4;
|
||||
|
||||
return (int)(totalScore * score_multiplier);
|
||||
});
|
||||
}
|
||||
|
||||
private void runScoreV2()
|
||||
{
|
||||
int maxCombo = sliderMaxCombo.Current.Value;
|
||||
|
||||
int currentCombo = 0;
|
||||
double comboPortion = 0;
|
||||
double currentBaseScore = 0;
|
||||
double maxBaseScore = 0;
|
||||
int currentHits = 0;
|
||||
|
||||
for (int i = 0; i < maxCombo; i++)
|
||||
applyHitV2(base_great);
|
||||
|
||||
double comboPortionMax = comboPortion;
|
||||
|
||||
currentCombo = 0;
|
||||
comboPortion = 0;
|
||||
currentBaseScore = 0;
|
||||
maxBaseScore = 0;
|
||||
currentHits = 0;
|
||||
|
||||
void applyHitV2(int baseScore)
|
||||
{
|
||||
maxBaseScore += base_great;
|
||||
currentBaseScore += baseScore;
|
||||
comboPortion += baseScore * (1 + ++currentCombo / 10.0);
|
||||
|
||||
currentHits++;
|
||||
}
|
||||
|
||||
runForAlgorithm("ScoreV2", Color4.OrangeRed,
|
||||
() => applyHitV2(base_great),
|
||||
() => applyHitV2(base_ok),
|
||||
() =>
|
||||
{
|
||||
currentHits++;
|
||||
maxBaseScore += base_great;
|
||||
currentCombo = 0;
|
||||
}, () =>
|
||||
{
|
||||
double accuracy = currentBaseScore / maxBaseScore;
|
||||
|
||||
return (int)Math.Round
|
||||
(
|
||||
700000 * comboPortion / comboPortionMax +
|
||||
300000 * Math.Pow(accuracy, 10) * ((double)currentHits / maxCombo)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private void runForProcessor(string name, Color4 colour, ScoreProcessor processor)
|
||||
{
|
||||
int maxCombo = sliderMaxCombo.Current.Value;
|
||||
|
||||
var beatmap = new OsuBeatmap();
|
||||
for (int i = 0; i < maxCombo; i++)
|
||||
beatmap.HitObjects.Add(new HitCircle());
|
||||
|
||||
processor.ApplyBeatmap(beatmap);
|
||||
|
||||
runForAlgorithm(name, colour,
|
||||
() => processor.ApplyResult(new OsuJudgementResult(new HitCircle(), new OsuJudgement()) { Type = HitResult.Great }),
|
||||
() => processor.ApplyResult(new OsuJudgementResult(new HitCircle(), new OsuJudgement()) { Type = HitResult.Ok }),
|
||||
() => processor.ApplyResult(new OsuJudgementResult(new HitCircle(), new OsuJudgement()) { Type = HitResult.Miss }),
|
||||
() => (int)processor.TotalScore.Value);
|
||||
}
|
||||
|
||||
private void runForAlgorithm(string name, Color4 colour, Action applyHit, Action applyNonPerfect, Action applyMiss, Func<int> getTotalScore)
|
||||
{
|
||||
int maxCombo = sliderMaxCombo.Current.Value;
|
||||
|
||||
List<float> results = new List<float>();
|
||||
|
||||
for (int i = 0; i < maxCombo; i++)
|
||||
{
|
||||
if (graphs.MissLocations.Contains(i))
|
||||
applyMiss();
|
||||
else if (graphs.NonPerfectLocations.Contains(i))
|
||||
applyNonPerfect();
|
||||
else
|
||||
applyHit();
|
||||
|
||||
results.Add(getTotalScore());
|
||||
}
|
||||
|
||||
graphs.Add(new LineGraph
|
||||
{
|
||||
Name = name,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
LineColour = colour,
|
||||
Values = results
|
||||
});
|
||||
|
||||
legend.Add(new OsuSpriteText
|
||||
{
|
||||
Colour = colour,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.5f,
|
||||
Text = $"{FontAwesome.Solid.Circle.Icon} {name}"
|
||||
});
|
||||
|
||||
legend.Add(new OsuSpriteText
|
||||
{
|
||||
Colour = colour,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.5f,
|
||||
Text = $"final score {getTotalScore():#,0}"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class GraphContainer : Container, IHasCustomTooltip<IEnumerable<LineGraph>>
|
||||
{
|
||||
public readonly BindableList<double> MissLocations = new BindableList<double>();
|
||||
public readonly BindableList<double> NonPerfectLocations = new BindableList<double>();
|
||||
|
||||
public Bindable<int> MaxCombo = new Bindable<int>();
|
||||
|
||||
protected override Container<Drawable> Content { get; } = new Container { RelativeSizeAxes = Axes.Both };
|
||||
|
||||
private readonly Box hoverLine;
|
||||
|
||||
private readonly Container missLines;
|
||||
private readonly Container verticalGridLines;
|
||||
|
||||
public int CurrentHoverCombo { get; private set; }
|
||||
|
||||
public GraphContainer()
|
||||
{
|
||||
InternalChild = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Colour = OsuColour.Gray(0.1f),
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
verticalGridLines = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
hoverLine = new Box
|
||||
{
|
||||
Colour = Color4.Yellow,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Origin = Anchor.TopCentre,
|
||||
Alpha = 0,
|
||||
Width = 1,
|
||||
},
|
||||
missLines = new Container
|
||||
{
|
||||
Alpha = 0.6f,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
Content,
|
||||
}
|
||||
};
|
||||
|
||||
MissLocations.BindCollectionChanged((_, _) => updateMissLocations());
|
||||
NonPerfectLocations.BindCollectionChanged((_, _) => updateMissLocations());
|
||||
|
||||
MaxCombo.BindValueChanged(_ =>
|
||||
{
|
||||
updateMissLocations();
|
||||
updateVerticalGridLines();
|
||||
}, true);
|
||||
}
|
||||
|
||||
private void updateVerticalGridLines()
|
||||
{
|
||||
verticalGridLines.Clear();
|
||||
|
||||
for (int i = 0; i < MaxCombo.Value; i++)
|
||||
{
|
||||
if (i % 100 == 0)
|
||||
{
|
||||
verticalGridLines.AddRange(new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Colour = OsuColour.Gray(0.2f),
|
||||
Origin = Anchor.TopCentre,
|
||||
Width = 1,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
RelativePositionAxes = Axes.X,
|
||||
X = (float)i / MaxCombo.Value,
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
RelativePositionAxes = Axes.X,
|
||||
X = (float)i / MaxCombo.Value,
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
Text = $"{i:#,0}",
|
||||
Rotation = -30,
|
||||
Y = -20,
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateMissLocations()
|
||||
{
|
||||
missLines.Clear();
|
||||
|
||||
foreach (int miss in MissLocations)
|
||||
{
|
||||
missLines.Add(new Box
|
||||
{
|
||||
Colour = Color4.Red,
|
||||
Origin = Anchor.TopCentre,
|
||||
Width = 1,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
RelativePositionAxes = Axes.X,
|
||||
X = (float)miss / MaxCombo.Value,
|
||||
});
|
||||
}
|
||||
|
||||
foreach (int miss in NonPerfectLocations)
|
||||
{
|
||||
missLines.Add(new Box
|
||||
{
|
||||
Colour = Color4.Orange,
|
||||
Origin = Anchor.TopCentre,
|
||||
Width = 1,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
RelativePositionAxes = Axes.X,
|
||||
X = (float)miss / MaxCombo.Value,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
hoverLine.Show();
|
||||
return base.OnHover(e);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e)
|
||||
{
|
||||
hoverLine.Hide();
|
||||
base.OnHoverLost(e);
|
||||
}
|
||||
|
||||
protected override bool OnMouseMove(MouseMoveEvent e)
|
||||
{
|
||||
CurrentHoverCombo = (int)(e.MousePosition.X / DrawWidth * MaxCombo.Value);
|
||||
|
||||
hoverLine.X = e.MousePosition.X;
|
||||
return base.OnMouseMove(e);
|
||||
}
|
||||
|
||||
protected override bool OnMouseDown(MouseDownEvent e)
|
||||
{
|
||||
if (e.Button == MouseButton.Left)
|
||||
MissLocations.Add(CurrentHoverCombo);
|
||||
else
|
||||
NonPerfectLocations.Add(CurrentHoverCombo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private GraphTooltip? tooltip;
|
||||
|
||||
public ITooltip<IEnumerable<LineGraph>> GetCustomTooltip() => tooltip ??= new GraphTooltip(this);
|
||||
|
||||
public IEnumerable<LineGraph> TooltipContent => Content.OfType<LineGraph>();
|
||||
|
||||
public class GraphTooltip : CompositeDrawable, ITooltip<IEnumerable<LineGraph>>
|
||||
{
|
||||
private readonly GraphContainer graphContainer;
|
||||
|
||||
private readonly OsuTextFlowContainer textFlow;
|
||||
|
||||
public GraphTooltip(GraphContainer graphContainer)
|
||||
{
|
||||
this.graphContainer = graphContainer;
|
||||
AutoSizeAxes = Axes.Both;
|
||||
|
||||
Masking = true;
|
||||
CornerRadius = 10;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Colour = OsuColour.Gray(0.15f),
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
textFlow = new OsuTextFlowContainer
|
||||
{
|
||||
Colour = Color4.White,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding(10),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private int? lastContentCombo;
|
||||
|
||||
public void SetContent(IEnumerable<LineGraph> content)
|
||||
{
|
||||
int relevantCombo = graphContainer.CurrentHoverCombo;
|
||||
|
||||
if (lastContentCombo == relevantCombo)
|
||||
return;
|
||||
|
||||
lastContentCombo = relevantCombo;
|
||||
textFlow.Clear();
|
||||
|
||||
textFlow.AddParagraph($"At combo {relevantCombo}:");
|
||||
|
||||
foreach (var graph in content)
|
||||
{
|
||||
float valueAtHover = graph.Values.ElementAt(relevantCombo);
|
||||
float ofTotal = valueAtHover / graph.Values.Last();
|
||||
|
||||
textFlow.AddParagraph($"{graph.Name}: {valueAtHover:#,0} ({ofTotal * 100:N0}% of final)\n", st => st.Colour = graph.LineColour);
|
||||
}
|
||||
}
|
||||
|
||||
public void Move(Vector2 pos) => this.MoveTo(pos);
|
||||
}
|
||||
}
|
||||
}
|
@ -214,7 +214,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
private void addControlPoints(IList<MultiplierControlPoint> controlPoints, double sequenceStartTime)
|
||||
{
|
||||
controlPoints.ForEach(point => point.StartTime += sequenceStartTime);
|
||||
controlPoints.ForEach(point => point.Time += sequenceStartTime);
|
||||
|
||||
scrollContainers.ForEach(container =>
|
||||
{
|
||||
@ -224,7 +224,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
foreach (var playfield in playfields)
|
||||
{
|
||||
foreach (var controlPoint in controlPoints)
|
||||
playfield.Add(createDrawablePoint(playfield, controlPoint.StartTime));
|
||||
playfield.Add(createDrawablePoint(playfield, controlPoint.Time));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,14 +97,23 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCurrentItemDoesNotHaveDeleteButton()
|
||||
public void TestSingleItemDoesNotHaveDeleteButton()
|
||||
{
|
||||
AddStep("set all players queue mode", () => MultiplayerClient.ChangeSettings(new MultiplayerRoomSettings { QueueMode = QueueMode.AllPlayers }).WaitSafely());
|
||||
AddUntilStep("wait for queue mode change", () => MultiplayerClient.ClientAPIRoom?.QueueMode.Value == QueueMode.AllPlayers);
|
||||
|
||||
assertDeleteButtonVisibility(0, false);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCurrentItemHasDeleteButtonIfNotSingle()
|
||||
{
|
||||
AddStep("set all players queue mode", () => MultiplayerClient.ChangeSettings(new MultiplayerRoomSettings { QueueMode = QueueMode.AllPlayers }).WaitSafely());
|
||||
AddUntilStep("wait for queue mode change", () => MultiplayerClient.ClientAPIRoom?.QueueMode.Value == QueueMode.AllPlayers);
|
||||
|
||||
addPlaylistItem(() => API.LocalUser.Value.OnlineID);
|
||||
|
||||
assertDeleteButtonVisibility(0, false);
|
||||
assertDeleteButtonVisibility(0, true);
|
||||
assertDeleteButtonVisibility(1, true);
|
||||
|
||||
AddStep("finish current item", () => MultiplayerClient.FinishCurrentItem().WaitSafely());
|
||||
|
@ -25,6 +25,7 @@ using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Menu;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Navigation
|
||||
{
|
||||
@ -79,6 +80,16 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
[Resolved]
|
||||
private OsuGameBase gameBase { get; set; }
|
||||
|
||||
[Test]
|
||||
public void TestCursorHidesWhenIdle()
|
||||
{
|
||||
AddStep("click mouse", () => InputManager.Click(MouseButton.Left));
|
||||
AddUntilStep("wait until idle", () => Game.IsIdle.Value);
|
||||
AddUntilStep("menu cursor hidden", () => Game.GlobalCursorDisplay.MenuCursor.ActiveCursor.Alpha == 0);
|
||||
AddStep("click mouse", () => InputManager.Click(MouseButton.Left));
|
||||
AddUntilStep("menu cursor shown", () => Game.GlobalCursorDisplay.MenuCursor.ActiveCursor.Alpha == 1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNullRulesetHandled()
|
||||
{
|
||||
|
@ -3,18 +3,17 @@
|
||||
|
||||
#nullable disable
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Graphics.UserInterfaceV2;
|
||||
using osu.Game.Tests.Visual.UserInterface;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Settings
|
||||
{
|
||||
public class TestSceneDirectorySelector : OsuTestScene
|
||||
public class TestSceneDirectorySelector : ThemeComparisonTestScene
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
protected override Drawable CreateContent() => new OsuDirectorySelector
|
||||
{
|
||||
Add(new OsuDirectorySelector { RelativeSizeAxes = Axes.Both });
|
||||
}
|
||||
RelativeSizeAxes = Axes.Both
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -4,23 +4,43 @@
|
||||
#nullable disable
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.UserInterfaceV2;
|
||||
using osu.Game.Tests.Visual.UserInterface;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Settings
|
||||
{
|
||||
public class TestSceneFileSelector : OsuTestScene
|
||||
public class TestSceneFileSelector : ThemeComparisonTestScene
|
||||
{
|
||||
[Test]
|
||||
public void TestAllFiles()
|
||||
{
|
||||
AddStep("create", () => Child = new OsuFileSelector { RelativeSizeAxes = Axes.Both });
|
||||
}
|
||||
[Resolved]
|
||||
private OsuColour colours { get; set; }
|
||||
|
||||
[Test]
|
||||
public void TestJpgFilesOnly()
|
||||
{
|
||||
AddStep("create", () => Child = new OsuFileSelector(validFileExtensions: new[] { ".jpg" }) { RelativeSizeAxes = Axes.Both });
|
||||
AddStep("create", () =>
|
||||
{
|
||||
Cell(0, 0).Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = colours.GreySeaFoam
|
||||
},
|
||||
new OsuFileSelector(validFileExtensions: new[] { ".jpg" })
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
protected override Drawable CreateContent() => new OsuFileSelector
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -862,52 +862,6 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
AddAssert("Selection was remembered", () => eagerSelectedIDs.Count == 1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRandomFallbackOnNonMatchingPrevious()
|
||||
{
|
||||
List<BeatmapSetInfo> manySets = new List<BeatmapSetInfo>();
|
||||
|
||||
AddStep("populate maps", () =>
|
||||
{
|
||||
manySets.Clear();
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
manySets.Add(TestResources.CreateTestBeatmapSetInfo(3, new[]
|
||||
{
|
||||
// all taiko except for first
|
||||
rulesets.GetRuleset(i > 0 ? 1 : 0)
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
loadBeatmaps(manySets);
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
AddStep("Reset filter", () => carousel.Filter(new FilterCriteria(), false));
|
||||
|
||||
AddStep("select first beatmap", () => carousel.SelectBeatmap(manySets.First().Beatmaps.First()));
|
||||
|
||||
AddStep("Toggle non-matching filter", () =>
|
||||
{
|
||||
carousel.Filter(new FilterCriteria { SearchText = Guid.NewGuid().ToString() }, false);
|
||||
});
|
||||
|
||||
AddAssert("selection lost", () => carousel.SelectedBeatmapInfo == null);
|
||||
|
||||
AddStep("Restore different ruleset filter", () =>
|
||||
{
|
||||
carousel.Filter(new FilterCriteria { Ruleset = rulesets.GetRuleset(1) }, false);
|
||||
eagerSelectedIDs.Add(carousel.SelectedBeatmapSet!.ID);
|
||||
});
|
||||
|
||||
AddAssert("selection changed", () => !carousel.SelectedBeatmapInfo!.Equals(manySets.First().Beatmaps.First()));
|
||||
}
|
||||
|
||||
AddAssert("Selection was random", () => eagerSelectedIDs.Count > 2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestFilteringByUserStarDifficulty()
|
||||
{
|
||||
@ -955,6 +909,63 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
checkVisibleItemCount(true, 15);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCarouselSelectsNextWhenPreviousIsFiltered()
|
||||
{
|
||||
List<BeatmapSetInfo> sets = new List<BeatmapSetInfo>();
|
||||
|
||||
// 10 sets that go osu! -> taiko -> catch -> osu! -> ...
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var rulesetInfo = rulesets.AvailableRulesets.ElementAt(i % 3);
|
||||
sets.Add(TestResources.CreateTestBeatmapSetInfo(5, new[] { rulesetInfo }));
|
||||
}
|
||||
|
||||
// Sort mode is important to keep the ruleset order
|
||||
loadBeatmaps(sets, () => new FilterCriteria { Sort = SortMode.Title });
|
||||
setSelected(1, 1);
|
||||
|
||||
for (int i = 1; i < 10; i++)
|
||||
{
|
||||
var rulesetInfo = rulesets.AvailableRulesets.ElementAt(i % 3);
|
||||
AddStep($"Set ruleset to {rulesetInfo.ShortName}", () =>
|
||||
{
|
||||
carousel.Filter(new FilterCriteria { Ruleset = rulesetInfo, Sort = SortMode.Title }, false);
|
||||
});
|
||||
waitForSelection(i + 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCarouselSelectsBackwardsWhenDistanceIsShorter()
|
||||
{
|
||||
List<BeatmapSetInfo> sets = new List<BeatmapSetInfo>();
|
||||
|
||||
// 10 sets that go taiko, osu!, osu!, osu!, taiko, osu!, osu!, osu!, ...
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var rulesetInfo = rulesets.AvailableRulesets.ElementAt(i % 4 == 0 ? 1 : 0);
|
||||
sets.Add(TestResources.CreateTestBeatmapSetInfo(5, new[] { rulesetInfo }));
|
||||
}
|
||||
|
||||
// Sort mode is important to keep the ruleset order
|
||||
loadBeatmaps(sets, () => new FilterCriteria { Sort = SortMode.Title });
|
||||
|
||||
for (int i = 2; i < 10; i += 4)
|
||||
{
|
||||
setSelected(i, 1);
|
||||
AddStep("Set ruleset to taiko", () =>
|
||||
{
|
||||
carousel.Filter(new FilterCriteria { Ruleset = rulesets.AvailableRulesets.ElementAt(1), Sort = SortMode.Title }, false);
|
||||
});
|
||||
waitForSelection(i - 1, 1);
|
||||
AddStep("Remove ruleset filter", () =>
|
||||
{
|
||||
carousel.Filter(new FilterCriteria { Sort = SortMode.Title }, false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void loadBeatmaps(List<BeatmapSetInfo> beatmapSets = null, Func<FilterCriteria> initialCriteria = null, Action<BeatmapCarousel> carouselAdjust = null, int? count = null,
|
||||
bool randomDifficulties = false)
|
||||
{
|
||||
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.ObjectExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
@ -150,6 +151,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
public void TestUpdateLocalBeatmap()
|
||||
{
|
||||
DialogOverlay dialogOverlay = null!;
|
||||
UpdateBeatmapSetButton? updateButton = null;
|
||||
|
||||
AddStep("create carousel with dialog overlay", () =>
|
||||
{
|
||||
@ -176,7 +178,8 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
carousel.UpdateBeatmapSet(testBeatmapSetInfo);
|
||||
});
|
||||
|
||||
AddStep("click button", () => getUpdateButton()?.TriggerClick());
|
||||
AddUntilStep("wait for update button", () => (updateButton = getUpdateButton()) != null);
|
||||
AddStep("click button", () => updateButton.AsNonNull().TriggerClick());
|
||||
|
||||
AddAssert("dialog displayed", () => dialogOverlay.CurrentDialog is UpdateLocalConfirmationDialog);
|
||||
AddStep("click confirmation", () =>
|
||||
|
@ -15,6 +15,7 @@ using osu.Game.Graphics.Cursor;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
@ -81,25 +82,24 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
};
|
||||
|
||||
AddToggleStep("Smooth transitions", b => cursorBoxes.ForEach(box => box.SmoothTransition = b));
|
||||
|
||||
testUserCursor();
|
||||
testLocalCursor();
|
||||
testUserCursorOverride();
|
||||
testMultipleLocalCursors();
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public void SetUp() => Schedule(moveOut);
|
||||
|
||||
/// <summary>
|
||||
/// -- Green Box --
|
||||
/// Tests whether hovering in and out of a drawable that provides the user cursor (green)
|
||||
/// results in the correct visibility state for that cursor.
|
||||
/// </summary>
|
||||
private void testUserCursor()
|
||||
[Test]
|
||||
public void TestUserCursor()
|
||||
{
|
||||
AddStep("Move to green area", () => InputManager.MoveMouseTo(cursorBoxes[0]));
|
||||
AddAssert("Check green cursor visible", () => checkVisible(cursorBoxes[0].MenuCursor));
|
||||
AddAssert("Check green cursor at mouse", () => checkAtMouse(cursorBoxes[0].MenuCursor));
|
||||
AddAssert("Check green cursor visible", () => checkVisible(cursorBoxes[0].Cursor));
|
||||
AddAssert("Check green cursor at mouse", () => checkAtMouse(cursorBoxes[0].Cursor));
|
||||
AddStep("Move out", moveOut);
|
||||
AddAssert("Check green cursor invisible", () => !checkVisible(cursorBoxes[0].MenuCursor));
|
||||
AddAssert("Check green cursor invisible", () => !checkVisible(cursorBoxes[0].Cursor));
|
||||
AddAssert("Check global cursor visible", () => checkVisible(globalCursorDisplay.MenuCursor));
|
||||
}
|
||||
|
||||
@ -108,15 +108,16 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
/// Tests whether hovering in and out of a drawable that provides a local cursor (purple)
|
||||
/// results in the correct visibility and state for that cursor.
|
||||
/// </summary>
|
||||
private void testLocalCursor()
|
||||
[Test]
|
||||
public void TestLocalCursor()
|
||||
{
|
||||
AddStep("Move to purple area", () => InputManager.MoveMouseTo(cursorBoxes[3]));
|
||||
AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].MenuCursor));
|
||||
AddAssert("Check purple cursor at mouse", () => checkAtMouse(cursorBoxes[3].MenuCursor));
|
||||
AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].Cursor));
|
||||
AddAssert("Check purple cursor at mouse", () => checkAtMouse(cursorBoxes[3].Cursor));
|
||||
AddAssert("Check global cursor visible", () => checkVisible(globalCursorDisplay.MenuCursor));
|
||||
AddAssert("Check global cursor at mouse", () => checkAtMouse(globalCursorDisplay.MenuCursor));
|
||||
AddStep("Move out", moveOut);
|
||||
AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].MenuCursor));
|
||||
AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].Cursor));
|
||||
AddAssert("Check global cursor visible", () => checkVisible(globalCursorDisplay.MenuCursor));
|
||||
}
|
||||
|
||||
@ -125,47 +126,98 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
/// Tests whether overriding a user cursor (green) with another user cursor (blue)
|
||||
/// results in the correct visibility and states for the cursors.
|
||||
/// </summary>
|
||||
private void testUserCursorOverride()
|
||||
[Test]
|
||||
public void TestUserCursorOverride()
|
||||
{
|
||||
AddStep("Move to blue-green boundary", () => InputManager.MoveMouseTo(cursorBoxes[1].ScreenSpaceDrawQuad.BottomRight - new Vector2(10)));
|
||||
AddAssert("Check blue cursor visible", () => checkVisible(cursorBoxes[1].MenuCursor));
|
||||
AddAssert("Check green cursor invisible", () => !checkVisible(cursorBoxes[0].MenuCursor));
|
||||
AddAssert("Check blue cursor at mouse", () => checkAtMouse(cursorBoxes[1].MenuCursor));
|
||||
AddAssert("Check blue cursor visible", () => checkVisible(cursorBoxes[1].Cursor));
|
||||
AddAssert("Check green cursor invisible", () => !checkVisible(cursorBoxes[0].Cursor));
|
||||
AddAssert("Check blue cursor at mouse", () => checkAtMouse(cursorBoxes[1].Cursor));
|
||||
AddStep("Move out", moveOut);
|
||||
AddAssert("Check blue cursor not visible", () => !checkVisible(cursorBoxes[1].MenuCursor));
|
||||
AddAssert("Check green cursor not visible", () => !checkVisible(cursorBoxes[0].MenuCursor));
|
||||
AddAssert("Check blue cursor not visible", () => !checkVisible(cursorBoxes[1].Cursor));
|
||||
AddAssert("Check green cursor not visible", () => !checkVisible(cursorBoxes[0].Cursor));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// -- Yellow-Purple Box Boundary --
|
||||
/// Tests whether multiple local cursors (purple + yellow) may be visible and at the mouse position at the same time.
|
||||
/// </summary>
|
||||
private void testMultipleLocalCursors()
|
||||
[Test]
|
||||
public void TestMultipleLocalCursors()
|
||||
{
|
||||
AddStep("Move to yellow-purple boundary", () => InputManager.MoveMouseTo(cursorBoxes[5].ScreenSpaceDrawQuad.BottomRight - new Vector2(10)));
|
||||
AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].MenuCursor));
|
||||
AddAssert("Check purple cursor at mouse", () => checkAtMouse(cursorBoxes[3].MenuCursor));
|
||||
AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].MenuCursor));
|
||||
AddAssert("Check yellow cursor at mouse", () => checkAtMouse(cursorBoxes[5].MenuCursor));
|
||||
AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].Cursor));
|
||||
AddAssert("Check purple cursor at mouse", () => checkAtMouse(cursorBoxes[3].Cursor));
|
||||
AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].Cursor));
|
||||
AddAssert("Check yellow cursor at mouse", () => checkAtMouse(cursorBoxes[5].Cursor));
|
||||
AddStep("Move out", moveOut);
|
||||
AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].MenuCursor));
|
||||
AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].MenuCursor));
|
||||
AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].Cursor));
|
||||
AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].Cursor));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// -- Yellow-Blue Box Boundary --
|
||||
/// Tests whether a local cursor (yellow) may be displayed along with a user cursor override (blue).
|
||||
/// </summary>
|
||||
private void testUserOverrideWithLocal()
|
||||
[Test]
|
||||
public void TestUserOverrideWithLocal()
|
||||
{
|
||||
AddStep("Move to yellow-blue boundary", () => InputManager.MoveMouseTo(cursorBoxes[5].ScreenSpaceDrawQuad.TopRight - new Vector2(10)));
|
||||
AddAssert("Check blue cursor visible", () => checkVisible(cursorBoxes[1].MenuCursor));
|
||||
AddAssert("Check blue cursor at mouse", () => checkAtMouse(cursorBoxes[1].MenuCursor));
|
||||
AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].MenuCursor));
|
||||
AddAssert("Check yellow cursor at mouse", () => checkAtMouse(cursorBoxes[5].MenuCursor));
|
||||
AddStep("Move to yellow-blue boundary", () => InputManager.MoveMouseTo(cursorBoxes[5].ScreenSpaceDrawQuad.TopRight - new Vector2(10, 0)));
|
||||
AddAssert("Check blue cursor visible", () => checkVisible(cursorBoxes[1].Cursor));
|
||||
AddAssert("Check blue cursor at mouse", () => checkAtMouse(cursorBoxes[1].Cursor));
|
||||
AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].Cursor));
|
||||
AddAssert("Check yellow cursor at mouse", () => checkAtMouse(cursorBoxes[5].Cursor));
|
||||
AddStep("Move out", moveOut);
|
||||
AddAssert("Check blue cursor invisible", () => !checkVisible(cursorBoxes[1].MenuCursor));
|
||||
AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].MenuCursor));
|
||||
AddAssert("Check blue cursor invisible", () => !checkVisible(cursorBoxes[1].Cursor));
|
||||
AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].Cursor));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures non-mouse input hides global cursor on a "local cursor" area (which doesn't hide global cursor).
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestKeyboardLocalCursor([Values] bool clickToShow)
|
||||
{
|
||||
AddStep("Enable cursor hiding", () => globalCursorDisplay.MenuCursor.HideCursorOnNonMouseInput = true);
|
||||
AddStep("Move to purple area", () => InputManager.MoveMouseTo(cursorBoxes[3].ScreenSpaceDrawQuad.Centre + new Vector2(10, 0)));
|
||||
AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].Cursor));
|
||||
AddAssert("Check global cursor alpha is 1", () => globalCursorDisplay.MenuCursor.Alpha == 1);
|
||||
|
||||
AddStep("Press key", () => InputManager.Key(Key.A));
|
||||
AddAssert("Check purple cursor still visible", () => checkVisible(cursorBoxes[3].Cursor));
|
||||
AddUntilStep("Check global cursor alpha is 0", () => globalCursorDisplay.MenuCursor.ActiveCursor.Alpha == 0);
|
||||
|
||||
if (clickToShow)
|
||||
AddStep("Click mouse", () => InputManager.Click(MouseButton.Left));
|
||||
else
|
||||
AddStep("Move mouse", () => InputManager.MoveMouseTo(InputManager.CurrentState.Mouse.Position + Vector2.One));
|
||||
|
||||
AddAssert("Check purple cursor still visible", () => checkVisible(cursorBoxes[3].Cursor));
|
||||
AddUntilStep("Check global cursor alpha is 1", () => globalCursorDisplay.MenuCursor.ActiveCursor.Alpha == 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures mouse input after non-mouse input doesn't show global cursor on a "user cursor" area (which hides global cursor).
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestKeyboardUserCursor([Values] bool clickToShow)
|
||||
{
|
||||
AddStep("Enable cursor hiding", () => globalCursorDisplay.MenuCursor.HideCursorOnNonMouseInput = true);
|
||||
AddStep("Move to green area", () => InputManager.MoveMouseTo(cursorBoxes[0]));
|
||||
AddAssert("Check green cursor visible", () => checkVisible(cursorBoxes[0].Cursor));
|
||||
AddAssert("Check global cursor alpha is 0", () => !checkVisible(globalCursorDisplay.MenuCursor) && globalCursorDisplay.MenuCursor.ActiveCursor.Alpha == 0);
|
||||
|
||||
AddStep("Press key", () => InputManager.Key(Key.A));
|
||||
AddAssert("Check green cursor still visible", () => checkVisible(cursorBoxes[0].Cursor));
|
||||
AddAssert("Check global cursor alpha is still 0", () => !checkVisible(globalCursorDisplay.MenuCursor) && globalCursorDisplay.MenuCursor.ActiveCursor.Alpha == 0);
|
||||
|
||||
if (clickToShow)
|
||||
AddStep("Click mouse", () => InputManager.Click(MouseButton.Left));
|
||||
else
|
||||
AddStep("Move mouse", () => InputManager.MoveMouseTo(InputManager.CurrentState.Mouse.Position + Vector2.One));
|
||||
|
||||
AddAssert("Check green cursor still visible", () => checkVisible(cursorBoxes[0].Cursor));
|
||||
AddAssert("Check global cursor alpha is still 0", () => !checkVisible(globalCursorDisplay.MenuCursor) && globalCursorDisplay.MenuCursor.ActiveCursor.Alpha == 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -191,7 +243,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
public bool SmoothTransition;
|
||||
|
||||
public CursorContainer MenuCursor { get; }
|
||||
public CursorContainer Cursor { get; }
|
||||
public bool ProvidingUserCursor { get; }
|
||||
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => base.ReceivePositionalInputAt(screenSpacePos) || (SmoothTransition && !ProvidingUserCursor);
|
||||
@ -218,7 +270,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
Origin = Anchor.Centre,
|
||||
Text = providesUserCursor ? "User cursor" : "Local cursor"
|
||||
},
|
||||
MenuCursor = new TestCursorContainer
|
||||
Cursor = new TestCursorContainer
|
||||
{
|
||||
State = { Value = providesUserCursor ? Visibility.Hidden : Visibility.Visible },
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Overlays.Settings;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@ -24,6 +25,8 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
private readonly Bindable<float> safeAreaPaddingLeft = new BindableFloat { MinValue = 0, MaxValue = 200 };
|
||||
private readonly Bindable<float> safeAreaPaddingRight = new BindableFloat { MinValue = 0, MaxValue = 200 };
|
||||
|
||||
private readonly Bindable<bool> applySafeAreaConsiderations = new Bindable<bool>(true);
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
@ -84,6 +87,11 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
Current = safeAreaPaddingRight,
|
||||
LabelText = "Right"
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Apply",
|
||||
Current = applySafeAreaConsiderations,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -93,6 +101,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
safeAreaPaddingBottom.BindValueChanged(_ => updateSafeArea());
|
||||
safeAreaPaddingLeft.BindValueChanged(_ => updateSafeArea());
|
||||
safeAreaPaddingRight.BindValueChanged(_ => updateSafeArea());
|
||||
applySafeAreaConsiderations.BindValueChanged(_ => updateSafeArea());
|
||||
});
|
||||
|
||||
base.SetUpSteps();
|
||||
@ -107,6 +116,8 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
Left = safeAreaPaddingLeft.Value,
|
||||
Right = safeAreaPaddingRight.Value,
|
||||
};
|
||||
|
||||
Game.LocalConfig.SetValue(OsuSetting.SafeAreaConsiderations, applySafeAreaConsiderations.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -5,12 +5,14 @@
|
||||
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Graphics.UserInterfaceV2;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Settings;
|
||||
using osuTK;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.UserInterface
|
||||
@ -20,11 +22,17 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
private SettingsToolboxGroup group;
|
||||
|
||||
[Cached]
|
||||
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
|
||||
|
||||
[SetUp]
|
||||
public void SetUp() => Schedule(() =>
|
||||
{
|
||||
Child = group = new SettingsToolboxGroup("example")
|
||||
{
|
||||
Scale = new Vector2(3),
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new RoundedButton
|
||||
|
Reference in New Issue
Block a user