mirror of
https://github.com/ppy/osu.git
synced 2025-02-21 03:02:54 +08:00
Merge branch 'master' into argon-health-rework
This commit is contained in:
commit
1fd85b79db
@ -51,10 +51,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
|||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
hitObjectPosition = hitObject.PositionBindable.GetBoundCopy();
|
hitObjectPosition = hitObject.PositionBindable.GetBoundCopy();
|
||||||
hitObjectPosition.BindValueChanged(_ => updateConnectingPath());
|
hitObjectPosition.BindValueChanged(_ => Scheduler.AddOnce(updateConnectingPath));
|
||||||
|
|
||||||
pathVersion = hitObject.Path.Version.GetBoundCopy();
|
pathVersion = hitObject.Path.Version.GetBoundCopy();
|
||||||
pathVersion.BindValueChanged(_ => updateConnectingPath());
|
pathVersion.BindValueChanged(_ => Scheduler.AddOnce(updateConnectingPath));
|
||||||
|
|
||||||
updateConnectingPath();
|
updateConnectingPath();
|
||||||
}
|
}
|
||||||
|
@ -244,6 +244,15 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
else if (slidingSample.IsPlaying)
|
else if (slidingSample.IsPlaying)
|
||||||
slidingSample.Stop();
|
slidingSample.Stop();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void UpdateAfterChildren()
|
||||||
|
{
|
||||||
|
base.UpdateAfterChildren();
|
||||||
|
|
||||||
|
// During slider path editing, the PlaySliderBody is scheduled to refresh once on Update.
|
||||||
|
// It is crucial to perform the code below in UpdateAfterChildren. This ensures that the SliderBody has the opportunity
|
||||||
|
// to update its Size and PathOffset beforehand, ensuring correct placement.
|
||||||
|
|
||||||
double completionProgress = Math.Clamp((Time.Current - HitObject.StartTime) / HitObject.Duration, 0, 1);
|
double completionProgress = Math.Clamp((Time.Current - HitObject.StartTime) / HitObject.Duration, 0, 1);
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
repeatCount = value;
|
repeatCount = value;
|
||||||
updateNestedPositions();
|
endPositionCache.Invalidate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,7 +165,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
public Slider()
|
public Slider()
|
||||||
{
|
{
|
||||||
SamplesBindable.CollectionChanged += (_, _) => UpdateNestedSamples();
|
SamplesBindable.CollectionChanged += (_, _) => UpdateNestedSamples();
|
||||||
Path.Version.ValueChanged += _ => updateNestedPositions();
|
Path.Version.ValueChanged += _ => endPositionCache.Invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, IBeatmapDifficultyInfo difficulty)
|
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, IBeatmapDifficultyInfo difficulty)
|
||||||
|
@ -14,16 +14,16 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class SliderEndCircle : HitCircle
|
public abstract class SliderEndCircle : HitCircle
|
||||||
{
|
{
|
||||||
private readonly Slider slider;
|
protected readonly Slider Slider;
|
||||||
|
|
||||||
protected SliderEndCircle(Slider slider)
|
protected SliderEndCircle(Slider slider)
|
||||||
{
|
{
|
||||||
this.slider = slider;
|
Slider = slider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int RepeatIndex { get; set; }
|
public int RepeatIndex { get; set; }
|
||||||
|
|
||||||
public double SpanDuration => slider.SpanDuration;
|
public double SpanDuration => Slider.SpanDuration;
|
||||||
|
|
||||||
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, IBeatmapDifficultyInfo difficulty)
|
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, IBeatmapDifficultyInfo difficulty)
|
||||||
{
|
{
|
||||||
@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// The first end circle should fade in with the slider.
|
// The first end circle should fade in with the slider.
|
||||||
TimePreempt += StartTime - slider.StartTime;
|
TimePreempt += StartTime - Slider.StartTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default
|
|||||||
ScaleBindable.BindValueChanged(scale => PathRadius = OsuHitObject.OBJECT_RADIUS * scale.NewValue, true);
|
ScaleBindable.BindValueChanged(scale => PathRadius = OsuHitObject.OBJECT_RADIUS * scale.NewValue, true);
|
||||||
|
|
||||||
pathVersion = drawableSlider.PathVersion.GetBoundCopy();
|
pathVersion = drawableSlider.PathVersion.GetBoundCopy();
|
||||||
pathVersion.BindValueChanged(_ => Refresh());
|
pathVersion.BindValueChanged(_ => Scheduler.AddOnce(Refresh));
|
||||||
|
|
||||||
AccentColourBindable = drawableObject.AccentColour.GetBoundCopy();
|
AccentColourBindable = drawableObject.AccentColour.GetBoundCopy();
|
||||||
AccentColourBindable.BindValueChanged(accent => AccentColour = GetBodyAccentColour(skin, accent.NewValue), true);
|
AccentColourBindable.BindValueChanged(accent => AccentColour = GetBodyAccentColour(skin, accent.NewValue), true);
|
||||||
|
@ -57,17 +57,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
InternalChild = cursorScaleContainer = new Container
|
InternalChild = CreateCursorContent();
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Child = cursorSprite = new SkinnableDrawable(new OsuSkinComponentLookup(OsuSkinComponents.Cursor), _ => new DefaultCursor(), confineMode: ConfineMode.NoScaling)
|
|
||||||
{
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
userCursorScale = config.GetBindable<float>(OsuSetting.GameplayCursorSize);
|
userCursorScale = config.GetBindable<float>(OsuSetting.GameplayCursorSize);
|
||||||
userCursorScale.ValueChanged += _ => cursorScale.Value = CalculateCursorScale();
|
userCursorScale.ValueChanged += _ => cursorScale.Value = CalculateCursorScale();
|
||||||
@ -84,6 +74,18 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
|||||||
cursorScale.Value = CalculateCursorScale();
|
cursorScale.Value = CalculateCursorScale();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual Drawable CreateCursorContent() => cursorScaleContainer = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Child = cursorSprite = new SkinnableDrawable(new OsuSkinComponentLookup(OsuSkinComponents.Cursor), _ => new DefaultCursor(), confineMode: ConfineMode.NoScaling)
|
||||||
|
{
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
protected virtual float CalculateCursorScale()
|
protected virtual float CalculateCursorScale()
|
||||||
{
|
{
|
||||||
float scale = userCursorScale.Value;
|
float scale = userCursorScale.Value;
|
||||||
|
@ -65,17 +65,24 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
public override bool HandlePositionalInput => true;
|
public override bool HandlePositionalInput => true;
|
||||||
|
|
||||||
public Action ResumeRequested;
|
public Action ResumeRequested;
|
||||||
|
private Container scaleTransitionContainer;
|
||||||
|
|
||||||
public OsuClickToResumeCursor()
|
public OsuClickToResumeCursor()
|
||||||
{
|
{
|
||||||
RelativePositionAxes = Axes.Both;
|
RelativePositionAxes = Axes.Both;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override float CalculateCursorScale()
|
protected override Container CreateCursorContent() => scaleTransitionContainer = new Container
|
||||||
{
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Child = base.CreateCursorContent(),
|
||||||
|
};
|
||||||
|
|
||||||
|
protected override float CalculateCursorScale() =>
|
||||||
// Force minimum cursor size so it's easily clickable
|
// Force minimum cursor size so it's easily clickable
|
||||||
return Math.Max(1f, base.CalculateCursorScale());
|
Math.Max(1f, base.CalculateCursorScale());
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool OnHover(HoverEvent e)
|
protected override bool OnHover(HoverEvent e)
|
||||||
{
|
{
|
||||||
@ -98,7 +105,7 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
if (!IsHovered)
|
if (!IsHovered)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
this.ScaleTo(2, TRANSITION_TIME, Easing.OutQuint);
|
scaleTransitionContainer.ScaleTo(2, TRANSITION_TIME, Easing.OutQuint);
|
||||||
|
|
||||||
ResumeRequested?.Invoke();
|
ResumeRequested?.Invoke();
|
||||||
return true;
|
return true;
|
||||||
@ -114,7 +121,10 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
public void Appear() => Schedule(() =>
|
public void Appear() => Schedule(() =>
|
||||||
{
|
{
|
||||||
updateColour();
|
updateColour();
|
||||||
this.ScaleTo(4).Then().ScaleTo(1, 1000, Easing.OutQuint);
|
|
||||||
|
// importantly, we perform the scale transition on an underlying container rather than the whole cursor
|
||||||
|
// to prevent attempts of abuse by the scale change in the cursor's hitbox (see: https://github.com/ppy/osu/issues/26477).
|
||||||
|
scaleTransitionContainer.ScaleTo(4).Then().ScaleTo(1, 1000, Easing.OutQuint);
|
||||||
});
|
});
|
||||||
|
|
||||||
private void updateColour()
|
private void updateColour()
|
||||||
|
@ -19,8 +19,10 @@ using osu.Game.Beatmaps.Drawables;
|
|||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.Cursor;
|
using osu.Game.Graphics.Cursor;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Models;
|
using osu.Game.Models;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Online.Chat;
|
||||||
using osu.Game.Online.Rooms;
|
using osu.Game.Online.Rooms;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
@ -302,6 +304,37 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSelectableMouseHandling()
|
||||||
|
{
|
||||||
|
bool resultsRequested = false;
|
||||||
|
|
||||||
|
AddStep("reset flag", () => resultsRequested = false);
|
||||||
|
createPlaylist(p =>
|
||||||
|
{
|
||||||
|
p.AllowSelection = true;
|
||||||
|
p.AllowShowingResults = true;
|
||||||
|
p.RequestResults = _ => resultsRequested = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("move mouse to first item title", () =>
|
||||||
|
{
|
||||||
|
var drawQuad = playlist.ChildrenOfType<LinkFlowContainer>().First().ScreenSpaceDrawQuad;
|
||||||
|
var location = (drawQuad.TopLeft + drawQuad.BottomLeft) / 2 + new Vector2(drawQuad.Width * 0.2f, 0);
|
||||||
|
InputManager.MoveMouseTo(location);
|
||||||
|
});
|
||||||
|
AddUntilStep("wait for text load", () => playlist.ChildrenOfType<DrawableLinkCompiler>().Any());
|
||||||
|
AddAssert("first item title not hovered", () => playlist.ChildrenOfType<DrawableLinkCompiler>().First().IsHovered, () => Is.False);
|
||||||
|
AddStep("click left mouse", () => InputManager.Click(MouseButton.Left));
|
||||||
|
AddUntilStep("first item selected", () => playlist.ChildrenOfType<DrawableRoomPlaylistItem>().First().IsSelectedItem, () => Is.True);
|
||||||
|
// implies being clickable.
|
||||||
|
AddUntilStep("first item title hovered", () => playlist.ChildrenOfType<DrawableLinkCompiler>().First().IsHovered, () => Is.True);
|
||||||
|
|
||||||
|
AddStep("move mouse to second item results button", () => InputManager.MoveMouseTo(playlist.ChildrenOfType<GrayButton>().ElementAt(5)));
|
||||||
|
AddStep("click left mouse", () => InputManager.Click(MouseButton.Left));
|
||||||
|
AddUntilStep("results requested", () => resultsRequested);
|
||||||
|
}
|
||||||
|
|
||||||
private void moveToItem(int index, Vector2? offset = null)
|
private void moveToItem(int index, Vector2? offset = null)
|
||||||
=> AddStep($"move mouse to item {index}", () => InputManager.MoveMouseTo(playlist.ChildrenOfType<DrawableRoomPlaylistItem>().ElementAt(index), offset));
|
=> AddStep($"move mouse to item {index}", () => InputManager.MoveMouseTo(playlist.ChildrenOfType<DrawableRoomPlaylistItem>().ElementAt(index), offset));
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ using osu.Game.Graphics.UserInterface;
|
|||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.API.Requests;
|
using osu.Game.Online.API.Requests;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
|
using osu.Game.Online.Placeholders;
|
||||||
using osu.Game.Online.Rooms;
|
using osu.Game.Online.Rooms;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
@ -49,8 +50,8 @@ namespace osu.Game.Tests.Visual.Playlists
|
|||||||
|
|
||||||
// Previous test instances of the results screen may still exist at this point so wait for
|
// Previous test instances of the results screen may still exist at this point so wait for
|
||||||
// those screens to be cleaned up by the base SetUpSteps before re-initialising test state.
|
// those screens to be cleaned up by the base SetUpSteps before re-initialising test state.
|
||||||
// The the screen also holds a leased Beatmap bindable so reassigning it must happen after
|
// The screen also holds a leased Beatmap bindable so reassigning it must happen after
|
||||||
// the screen as been exited.
|
// the screen has been exited.
|
||||||
AddStep("initialise user scores and beatmap", () =>
|
AddStep("initialise user scores and beatmap", () =>
|
||||||
{
|
{
|
||||||
lowestScoreId = 1;
|
lowestScoreId = 1;
|
||||||
@ -63,8 +64,6 @@ namespace osu.Game.Tests.Visual.Playlists
|
|||||||
userScore.Statistics = new Dictionary<HitResult, int>();
|
userScore.Statistics = new Dictionary<HitResult, int>();
|
||||||
userScore.MaximumStatistics = new Dictionary<HitResult, int>();
|
userScore.MaximumStatistics = new Dictionary<HitResult, int>();
|
||||||
|
|
||||||
bindHandler();
|
|
||||||
|
|
||||||
// Beatmap is required to be an actual beatmap so the scores can get their scores correctly
|
// Beatmap is required to be an actual beatmap so the scores can get their scores correctly
|
||||||
// calculated for standardised scoring, else the tests that rely on ordering will fall over.
|
// calculated for standardised scoring, else the tests that rely on ordering will fall over.
|
||||||
Beatmap.Value = CreateWorkingBeatmap(Ruleset.Value);
|
Beatmap.Value = CreateWorkingBeatmap(Ruleset.Value);
|
||||||
@ -77,6 +76,7 @@ namespace osu.Game.Tests.Visual.Playlists
|
|||||||
AddStep("bind user score info handler", () => bindHandler(userScore: userScore));
|
AddStep("bind user score info handler", () => bindHandler(userScore: userScore));
|
||||||
|
|
||||||
createResults(() => userScore);
|
createResults(() => userScore);
|
||||||
|
waitForDisplay();
|
||||||
|
|
||||||
AddAssert("user score selected", () => this.ChildrenOfType<ScorePanel>().Single(p => p.Score.OnlineID == userScore.OnlineID).State == PanelState.Expanded);
|
AddAssert("user score selected", () => this.ChildrenOfType<ScorePanel>().Single(p => p.Score.OnlineID == userScore.OnlineID).State == PanelState.Expanded);
|
||||||
AddAssert($"score panel position is {real_user_position}",
|
AddAssert($"score panel position is {real_user_position}",
|
||||||
@ -86,7 +86,10 @@ namespace osu.Game.Tests.Visual.Playlists
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestShowNullUserScore()
|
public void TestShowNullUserScore()
|
||||||
{
|
{
|
||||||
|
AddStep("bind user score info handler", () => bindHandler());
|
||||||
|
|
||||||
createResults();
|
createResults();
|
||||||
|
waitForDisplay();
|
||||||
|
|
||||||
AddAssert("top score selected", () => this.ChildrenOfType<ScorePanel>().OrderByDescending(p => p.Score.TotalScore).First().State == PanelState.Expanded);
|
AddAssert("top score selected", () => this.ChildrenOfType<ScorePanel>().OrderByDescending(p => p.Score.TotalScore).First().State == PanelState.Expanded);
|
||||||
}
|
}
|
||||||
@ -97,6 +100,7 @@ namespace osu.Game.Tests.Visual.Playlists
|
|||||||
AddStep("bind user score info handler", () => bindHandler(true, userScore));
|
AddStep("bind user score info handler", () => bindHandler(true, userScore));
|
||||||
|
|
||||||
createResults(() => userScore);
|
createResults(() => userScore);
|
||||||
|
waitForDisplay();
|
||||||
|
|
||||||
AddAssert("more than 1 panel displayed", () => this.ChildrenOfType<ScorePanel>().Count() > 1);
|
AddAssert("more than 1 panel displayed", () => this.ChildrenOfType<ScorePanel>().Count() > 1);
|
||||||
AddAssert("user score selected", () => this.ChildrenOfType<ScorePanel>().Single(p => p.Score.OnlineID == userScore.OnlineID).State == PanelState.Expanded);
|
AddAssert("user score selected", () => this.ChildrenOfType<ScorePanel>().Single(p => p.Score.OnlineID == userScore.OnlineID).State == PanelState.Expanded);
|
||||||
@ -108,6 +112,7 @@ namespace osu.Game.Tests.Visual.Playlists
|
|||||||
AddStep("bind delayed handler", () => bindHandler(true));
|
AddStep("bind delayed handler", () => bindHandler(true));
|
||||||
|
|
||||||
createResults();
|
createResults();
|
||||||
|
waitForDisplay();
|
||||||
|
|
||||||
AddAssert("top score selected", () => this.ChildrenOfType<ScorePanel>().OrderByDescending(p => p.Score.TotalScore).First().State == PanelState.Expanded);
|
AddAssert("top score selected", () => this.ChildrenOfType<ScorePanel>().OrderByDescending(p => p.Score.TotalScore).First().State == PanelState.Expanded);
|
||||||
}
|
}
|
||||||
@ -115,10 +120,11 @@ namespace osu.Game.Tests.Visual.Playlists
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestFetchWhenScrolledToTheRight()
|
public void TestFetchWhenScrolledToTheRight()
|
||||||
{
|
{
|
||||||
createResults();
|
|
||||||
|
|
||||||
AddStep("bind delayed handler", () => bindHandler(true));
|
AddStep("bind delayed handler", () => bindHandler(true));
|
||||||
|
|
||||||
|
createResults();
|
||||||
|
waitForDisplay();
|
||||||
|
|
||||||
for (int i = 0; i < 2; i++)
|
for (int i = 0; i < 2; i++)
|
||||||
{
|
{
|
||||||
int beforePanelCount = 0;
|
int beforePanelCount = 0;
|
||||||
@ -134,12 +140,44 @@ namespace osu.Game.Tests.Visual.Playlists
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestNoMoreScoresToTheRight()
|
||||||
|
{
|
||||||
|
AddStep("bind delayed handler with scores", () => bindHandler(delayed: true));
|
||||||
|
|
||||||
|
createResults();
|
||||||
|
waitForDisplay();
|
||||||
|
|
||||||
|
int beforePanelCount = 0;
|
||||||
|
|
||||||
|
AddStep("get panel count", () => beforePanelCount = this.ChildrenOfType<ScorePanel>().Count());
|
||||||
|
AddStep("scroll to right", () => resultsScreen.ScorePanelList.ChildrenOfType<OsuScrollContainer>().Single().ScrollToEnd(false));
|
||||||
|
|
||||||
|
AddAssert("right loading spinner shown", () => resultsScreen.RightSpinner.State.Value == Visibility.Visible);
|
||||||
|
waitForDisplay();
|
||||||
|
|
||||||
|
AddAssert($"count increased by {scores_per_result}", () => this.ChildrenOfType<ScorePanel>().Count() >= beforePanelCount + scores_per_result);
|
||||||
|
AddAssert("right loading spinner hidden", () => resultsScreen.RightSpinner.State.Value == Visibility.Hidden);
|
||||||
|
|
||||||
|
AddStep("get panel count", () => beforePanelCount = this.ChildrenOfType<ScorePanel>().Count());
|
||||||
|
AddStep("bind delayed handler with no scores", () => bindHandler(delayed: true, noScores: true));
|
||||||
|
AddStep("scroll to right", () => resultsScreen.ScorePanelList.ChildrenOfType<OsuScrollContainer>().Single().ScrollToEnd(false));
|
||||||
|
|
||||||
|
AddAssert("right loading spinner shown", () => resultsScreen.RightSpinner.State.Value == Visibility.Visible);
|
||||||
|
waitForDisplay();
|
||||||
|
|
||||||
|
AddAssert("count not increased", () => this.ChildrenOfType<ScorePanel>().Count() == beforePanelCount);
|
||||||
|
AddAssert("right loading spinner hidden", () => resultsScreen.RightSpinner.State.Value == Visibility.Hidden);
|
||||||
|
AddAssert("no placeholders shown", () => this.ChildrenOfType<MessagePlaceholder>().Count(), () => Is.Zero);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestFetchWhenScrolledToTheLeft()
|
public void TestFetchWhenScrolledToTheLeft()
|
||||||
{
|
{
|
||||||
AddStep("bind user score info handler", () => bindHandler(userScore: userScore));
|
AddStep("bind user score info handler", () => bindHandler(userScore: userScore));
|
||||||
|
|
||||||
createResults(() => userScore);
|
createResults(() => userScore);
|
||||||
|
waitForDisplay();
|
||||||
|
|
||||||
AddStep("bind delayed handler", () => bindHandler(true));
|
AddStep("bind delayed handler", () => bindHandler(true));
|
||||||
|
|
||||||
@ -158,6 +196,15 @@ namespace osu.Game.Tests.Visual.Playlists
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestShowWithNoScores()
|
||||||
|
{
|
||||||
|
AddStep("bind user score info handler", () => bindHandler(noScores: true));
|
||||||
|
createResults();
|
||||||
|
AddAssert("no scores visible", () => !resultsScreen.ScorePanelList.GetScorePanels().Any());
|
||||||
|
AddAssert("placeholder shown", () => this.ChildrenOfType<MessagePlaceholder>().Count(), () => Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
|
||||||
private void createResults(Func<ScoreInfo> getScore = null)
|
private void createResults(Func<ScoreInfo> getScore = null)
|
||||||
{
|
{
|
||||||
AddStep("load results", () =>
|
AddStep("load results", () =>
|
||||||
@ -169,7 +216,6 @@ namespace osu.Game.Tests.Visual.Playlists
|
|||||||
});
|
});
|
||||||
|
|
||||||
AddUntilStep("wait for screen to load", () => resultsScreen.IsLoaded);
|
AddUntilStep("wait for screen to load", () => resultsScreen.IsLoaded);
|
||||||
waitForDisplay();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void waitForDisplay()
|
private void waitForDisplay()
|
||||||
@ -183,7 +229,7 @@ namespace osu.Game.Tests.Visual.Playlists
|
|||||||
AddWaitStep("wait for display", 5);
|
AddWaitStep("wait for display", 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void bindHandler(bool delayed = false, ScoreInfo userScore = null, bool failRequests = false) => ((DummyAPIAccess)API).HandleRequest = request =>
|
private void bindHandler(bool delayed = false, ScoreInfo userScore = null, bool failRequests = false, bool noScores = false) => ((DummyAPIAccess)API).HandleRequest = request =>
|
||||||
{
|
{
|
||||||
// pre-check for requests we should be handling (as they are scheduled below).
|
// pre-check for requests we should be handling (as they are scheduled below).
|
||||||
switch (request)
|
switch (request)
|
||||||
@ -219,7 +265,7 @@ namespace osu.Game.Tests.Visual.Playlists
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case IndexPlaylistScoresRequest i:
|
case IndexPlaylistScoresRequest i:
|
||||||
triggerSuccess(i, createIndexResponse(i));
|
triggerSuccess(i, createIndexResponse(i, noScores));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}, delay);
|
}, delay);
|
||||||
@ -301,10 +347,12 @@ namespace osu.Game.Tests.Visual.Playlists
|
|||||||
return multiplayerUserScore;
|
return multiplayerUserScore;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IndexedMultiplayerScores createIndexResponse(IndexPlaylistScoresRequest req)
|
private IndexedMultiplayerScores createIndexResponse(IndexPlaylistScoresRequest req, bool noScores = false)
|
||||||
{
|
{
|
||||||
var result = new IndexedMultiplayerScores();
|
var result = new IndexedMultiplayerScores();
|
||||||
|
|
||||||
|
if (noScores) return result;
|
||||||
|
|
||||||
string sort = req.IndexParams?.Properties["sort"].ToObject<string>() ?? "score_desc";
|
string sort = req.IndexParams?.Properties["sort"].ToObject<string>() ?? "score_desc";
|
||||||
|
|
||||||
for (int i = 1; i <= scores_per_result; i++)
|
for (int i = 1; i <= scores_per_result; i++)
|
||||||
|
@ -542,10 +542,23 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
|
|
||||||
AddStep("press enter", () => InputManager.Key(Key.Enter));
|
AddStep("press enter", () => InputManager.Key(Key.Enter));
|
||||||
AddAssert("hidden selected", () => getPanelForMod(typeof(OsuModHidden)).Active.Value);
|
AddAssert("hidden selected", () => getPanelForMod(typeof(OsuModHidden)).Active.Value);
|
||||||
|
AddAssert("all text selected in textbox", () =>
|
||||||
|
{
|
||||||
|
var textBox = modSelectOverlay.ChildrenOfType<SearchTextBox>().Single();
|
||||||
|
return textBox.SelectedText == textBox.Text;
|
||||||
|
});
|
||||||
|
|
||||||
AddStep("press enter again", () => InputManager.Key(Key.Enter));
|
AddStep("press enter again", () => InputManager.Key(Key.Enter));
|
||||||
AddAssert("hidden deselected", () => !getPanelForMod(typeof(OsuModHidden)).Active.Value);
|
AddAssert("hidden deselected", () => !getPanelForMod(typeof(OsuModHidden)).Active.Value);
|
||||||
|
|
||||||
|
AddStep("apply search matching nothing", () => modSelectOverlay.SearchTerm = "ZZZ");
|
||||||
|
AddStep("press enter", () => InputManager.Key(Key.Enter));
|
||||||
|
AddAssert("all text not selected in textbox", () =>
|
||||||
|
{
|
||||||
|
var textBox = modSelectOverlay.ChildrenOfType<SearchTextBox>().Single();
|
||||||
|
return textBox.SelectedText != textBox.Text;
|
||||||
|
});
|
||||||
|
|
||||||
AddStep("clear search", () => modSelectOverlay.SearchTerm = string.Empty);
|
AddStep("clear search", () => modSelectOverlay.SearchTerm = string.Empty);
|
||||||
AddStep("press enter", () => InputManager.Key(Key.Enter));
|
AddStep("press enter", () => InputManager.Key(Key.Enter));
|
||||||
AddAssert("mod select hidden", () => modSelectOverlay.State.Value == Visibility.Hidden);
|
AddAssert("mod select hidden", () => modSelectOverlay.State.Value == Visibility.Hidden);
|
||||||
|
@ -17,6 +17,7 @@ using osu.Game.Localisation;
|
|||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Overlays.Mods.Input;
|
using osu.Game.Overlays.Mods.Input;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
using osu.Game.Screens.OnlinePlay.Lounge.Components;
|
||||||
using osu.Game.Screens.Select;
|
using osu.Game.Screens.Select;
|
||||||
using osu.Game.Screens.Select.Filter;
|
using osu.Game.Screens.Select.Filter;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
@ -191,6 +192,8 @@ namespace osu.Game.Configuration
|
|||||||
SetDefault(OsuSetting.EditorLimitedDistanceSnap, false);
|
SetDefault(OsuSetting.EditorLimitedDistanceSnap, false);
|
||||||
SetDefault(OsuSetting.EditorShowSpeedChanges, false);
|
SetDefault(OsuSetting.EditorShowSpeedChanges, false);
|
||||||
|
|
||||||
|
SetDefault(OsuSetting.MultiplayerRoomFilter, RoomPermissionsFilter.All);
|
||||||
|
|
||||||
SetDefault(OsuSetting.LastProcessedMetadataId, -1);
|
SetDefault(OsuSetting.LastProcessedMetadataId, -1);
|
||||||
|
|
||||||
SetDefault(OsuSetting.ComboColourNormalisationAmount, 0.2f, 0f, 1f, 0.01f);
|
SetDefault(OsuSetting.ComboColourNormalisationAmount, 0.2f, 0f, 1f, 0.01f);
|
||||||
@ -423,5 +426,6 @@ namespace osu.Game.Configuration
|
|||||||
TouchDisableGameplayTaps,
|
TouchDisableGameplayTaps,
|
||||||
ModSelectTextSearchStartsActive,
|
ModSelectTextSearchStartsActive,
|
||||||
UserOnlineStatus,
|
UserOnlineStatus,
|
||||||
|
MultiplayerRoomFilter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,8 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
|
|
||||||
public void KillFocus() => textBox.KillFocus();
|
public void KillFocus() => textBox.KillFocus();
|
||||||
|
|
||||||
|
public bool SelectAll() => textBox.SelectAll();
|
||||||
|
|
||||||
public ShearedSearchTextBox()
|
public ShearedSearchTextBox()
|
||||||
{
|
{
|
||||||
Height = 42;
|
Height = 42;
|
||||||
|
@ -719,7 +719,10 @@ namespace osu.Game.Overlays.Mods
|
|||||||
ModState? firstMod = columnFlow.Columns.OfType<ModColumn>().FirstOrDefault(m => m.IsPresent)?.AvailableMods.FirstOrDefault(x => x.Visible);
|
ModState? firstMod = columnFlow.Columns.OfType<ModColumn>().FirstOrDefault(m => m.IsPresent)?.AvailableMods.FirstOrDefault(x => x.Visible);
|
||||||
|
|
||||||
if (firstMod is not null)
|
if (firstMod is not null)
|
||||||
|
{
|
||||||
firstMod.Active.Value = !firstMod.Active.Value;
|
firstMod.Active.Value = !firstMod.Active.Value;
|
||||||
|
SearchTextBox.SelectAll();
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -165,7 +165,11 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
{
|
{
|
||||||
d.SelectedItem.BindTarget = SelectedItem;
|
d.SelectedItem.BindTarget = SelectedItem;
|
||||||
d.RequestDeletion = i => RequestDeletion?.Invoke(i);
|
d.RequestDeletion = i => RequestDeletion?.Invoke(i);
|
||||||
d.RequestResults = i => RequestResults?.Invoke(i);
|
d.RequestResults = i =>
|
||||||
|
{
|
||||||
|
SelectedItem.Value = i;
|
||||||
|
RequestResults?.Invoke(i);
|
||||||
|
};
|
||||||
d.RequestEdit = i => RequestEdit?.Invoke(i);
|
d.RequestEdit = i => RequestEdit?.Invoke(i);
|
||||||
d.AllowReordering = AllowReordering;
|
d.AllowReordering = AllowReordering;
|
||||||
d.AllowDeletion = AllowDeletion;
|
d.AllowDeletion = AllowDeletion;
|
||||||
|
@ -118,8 +118,6 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
private ManageCollectionsDialog manageCollectionsDialog { get; set; }
|
private ManageCollectionsDialog manageCollectionsDialog { get; set; }
|
||||||
|
|
||||||
protected override bool ShouldBeConsideredForInput(Drawable child) => AllowReordering || AllowDeletion || !AllowSelection || SelectedItem.Value == Model;
|
|
||||||
|
|
||||||
public DrawableRoomPlaylistItem(PlaylistItem item)
|
public DrawableRoomPlaylistItem(PlaylistItem item)
|
||||||
: base(item)
|
: base(item)
|
||||||
{
|
{
|
||||||
@ -367,7 +365,7 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Margin = new MarginPadding { Left = 8, Right = 8 },
|
Margin = new MarginPadding { Left = 8, Right = 8 },
|
||||||
},
|
},
|
||||||
mainFillFlow = new FillFlowContainer
|
mainFillFlow = new MainFlow(() => SelectedItem.Value == Model || !AllowSelection)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.CentreLeft,
|
Anchor = Anchor.CentreLeft,
|
||||||
Origin = Anchor.CentreLeft,
|
Origin = Anchor.CentreLeft,
|
||||||
@ -670,5 +668,17 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
public LocalisableString TooltipText => avatar.TooltipText;
|
public LocalisableString TooltipText => avatar.TooltipText;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public partial class MainFlow : FillFlowContainer
|
||||||
|
{
|
||||||
|
private readonly Func<bool> allowInteraction;
|
||||||
|
|
||||||
|
public override bool PropagatePositionalInputSubTree => allowInteraction();
|
||||||
|
|
||||||
|
public MainFlow(Func<bool> allowInteraction)
|
||||||
|
{
|
||||||
|
this.allowInteraction = allowInteraction;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
@ -19,6 +19,7 @@ using osu.Framework.Input.Events;
|
|||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Framework.Threading;
|
using osu.Framework.Threading;
|
||||||
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Input;
|
using osu.Game.Input;
|
||||||
@ -77,6 +78,9 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
|||||||
[CanBeNull]
|
[CanBeNull]
|
||||||
private LeasedBindable<Room> selectionLease;
|
private LeasedBindable<Room> selectionLease;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
protected OsuConfigManager Config { get; private set; }
|
||||||
|
|
||||||
private readonly Bindable<FilterCriteria> filter = new Bindable<FilterCriteria>(new FilterCriteria());
|
private readonly Bindable<FilterCriteria> filter = new Bindable<FilterCriteria>(new FilterCriteria());
|
||||||
private readonly IBindable<bool> operationInProgress = new Bindable<bool>();
|
private readonly IBindable<bool> operationInProgress = new Bindable<bool>();
|
||||||
private readonly IBindable<bool> isIdle = new BindableBool();
|
private readonly IBindable<bool> isIdle = new BindableBool();
|
||||||
|
@ -12,6 +12,7 @@ using osu.Framework.Logging;
|
|||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.Multiplayer;
|
using osu.Game.Online.Multiplayer;
|
||||||
@ -51,6 +52,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
|||||||
roomAccessTypeDropdown = new SlimEnumDropdown<RoomPermissionsFilter>
|
roomAccessTypeDropdown = new SlimEnumDropdown<RoomPermissionsFilter>
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.None,
|
RelativeSizeAxes = Axes.None,
|
||||||
|
Current = Config.GetBindable<RoomPermissionsFilter>(OsuSetting.MultiplayerRoomFilter),
|
||||||
Width = 160,
|
Width = 160,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -461,12 +461,6 @@ namespace osu.Game.Screens.Play
|
|||||||
OnRetry = () => Restart(),
|
OnRetry = () => Restart(),
|
||||||
OnQuit = () => PerformExit(true),
|
OnQuit = () => PerformExit(true),
|
||||||
},
|
},
|
||||||
new GameplayOffsetControl
|
|
||||||
{
|
|
||||||
Margin = new MarginPadding(20),
|
|
||||||
Anchor = Anchor.CentreRight,
|
|
||||||
Origin = Anchor.CentreRight,
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ using System.Linq;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
@ -59,6 +60,15 @@ namespace osu.Game.Screens.Play
|
|||||||
}
|
}
|
||||||
|
|
||||||
AddInternal(new PlayerTouchInputDetector());
|
AddInternal(new PlayerTouchInputDetector());
|
||||||
|
|
||||||
|
// We probably want to move this display to something more global.
|
||||||
|
// Probably using the OSD somehow.
|
||||||
|
AddInternal(new GameplayOffsetControl
|
||||||
|
{
|
||||||
|
Margin = new MarginPadding(20),
|
||||||
|
Anchor = Anchor.CentreRight,
|
||||||
|
Origin = Anchor.CentreRight,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override GameplayClockContainer CreateGameplayClockContainer(WorkingBeatmap beatmap, double gameplayStart) => new MasterGameplayClockContainer(beatmap, gameplayStart)
|
protected override GameplayClockContainer CreateGameplayClockContainer(WorkingBeatmap beatmap, double gameplayStart) => new MasterGameplayClockContainer(beatmap, gameplayStart)
|
||||||
|
@ -21,7 +21,9 @@ using osu.Game.Graphics;
|
|||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Input.Bindings;
|
using osu.Game.Input.Bindings;
|
||||||
|
using osu.Game.Localisation;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Online.Placeholders;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
using osu.Game.Screens.Ranking.Statistics;
|
using osu.Game.Screens.Ranking.Statistics;
|
||||||
@ -245,6 +247,12 @@ namespace osu.Game.Screens.Ranking
|
|||||||
addScore(s);
|
addScore(s);
|
||||||
|
|
||||||
lastFetchCompleted = true;
|
lastFetchCompleted = true;
|
||||||
|
|
||||||
|
if (ScorePanelList.IsEmpty)
|
||||||
|
{
|
||||||
|
// This can happen if for example a beatmap that is part of a playlist hasn't been played yet.
|
||||||
|
VerticalScrollContent.Add(new MessagePlaceholder(LeaderboardStrings.NoRecordsYet));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
public override void OnEntering(ScreenTransitionEvent e)
|
public override void OnEntering(ScreenTransitionEvent e)
|
||||||
|
@ -49,6 +49,8 @@ namespace osu.Game.Screens.Ranking
|
|||||||
|
|
||||||
public bool AllPanelsVisible => flow.All(p => p.IsPresent);
|
public bool AllPanelsVisible => flow.All(p => p.IsPresent);
|
||||||
|
|
||||||
|
public bool IsEmpty => flow.Count == 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current scroll position.
|
/// The current scroll position.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
Loading…
Reference in New Issue
Block a user