mirror of
https://github.com/osukey/osukey.git
synced 2025-06-05 21:07:18 +09:00
Merge branch 'master' into master
This commit is contained in:
commit
74b15ec30c
@ -52,16 +52,25 @@ namespace osu.Game.Rulesets.Catch.Edit
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool HandleFlip(Direction direction)
|
public override bool HandleFlip(Direction direction, bool flipOverOrigin)
|
||||||
{
|
{
|
||||||
|
if (SelectedItems.Count == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// This could be implemented in the future if there's a requirement for it.
|
||||||
|
if (direction == Direction.Vertical)
|
||||||
|
return false;
|
||||||
|
|
||||||
var selectionRange = CatchHitObjectUtils.GetPositionRange(SelectedItems);
|
var selectionRange = CatchHitObjectUtils.GetPositionRange(SelectedItems);
|
||||||
|
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
|
||||||
EditorBeatmap.PerformOnSelection(h =>
|
EditorBeatmap.PerformOnSelection(h =>
|
||||||
{
|
{
|
||||||
if (h is CatchHitObject catchObject)
|
if (h is CatchHitObject catchObject)
|
||||||
changed |= handleFlip(selectionRange, catchObject);
|
changed |= handleFlip(selectionRange, catchObject, flipOverOrigin);
|
||||||
});
|
});
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,7 +125,7 @@ namespace osu.Game.Rulesets.Catch.Edit
|
|||||||
return Math.Clamp(deltaX, lowerBound, upperBound);
|
return Math.Clamp(deltaX, lowerBound, upperBound);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool handleFlip(PositionRange selectionRange, CatchHitObject hitObject)
|
private bool handleFlip(PositionRange selectionRange, CatchHitObject hitObject, bool flipOverOrigin)
|
||||||
{
|
{
|
||||||
switch (hitObject)
|
switch (hitObject)
|
||||||
{
|
{
|
||||||
@ -124,7 +133,7 @@ namespace osu.Game.Rulesets.Catch.Edit
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
case JuiceStream juiceStream:
|
case JuiceStream juiceStream:
|
||||||
juiceStream.OriginalX = selectionRange.GetFlippedPosition(juiceStream.OriginalX);
|
juiceStream.OriginalX = getFlippedPosition(juiceStream.OriginalX);
|
||||||
|
|
||||||
foreach (var point in juiceStream.Path.ControlPoints)
|
foreach (var point in juiceStream.Path.ControlPoints)
|
||||||
point.Position *= new Vector2(-1, 1);
|
point.Position *= new Vector2(-1, 1);
|
||||||
@ -133,9 +142,11 @@ namespace osu.Game.Rulesets.Catch.Edit
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
hitObject.OriginalX = selectionRange.GetFlippedPosition(hitObject.OriginalX);
|
hitObject.OriginalX = getFlippedPosition(hitObject.OriginalX);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float getFlippedPosition(float original) => flipOverOrigin ? CatchPlayfield.WIDTH - original : selectionRange.GetFlippedPosition(original);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/special-skin/hitcircleoverlay-1@2x.png
Executable file
BIN
osu.Game.Rulesets.Osu.Tests/Resources/special-skin/hitcircleoverlay-1@2x.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 40 KiB |
@ -10,6 +10,7 @@ using osu.Game.Extensions;
|
|||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.UI;
|
||||||
using osu.Game.Screens.Edit.Compose.Components;
|
using osu.Game.Screens.Edit.Compose.Components;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
@ -84,18 +85,28 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool HandleFlip(Direction direction)
|
public override bool HandleFlip(Direction direction, bool flipOverOrigin)
|
||||||
{
|
{
|
||||||
var hitObjects = selectedMovableObjects;
|
var hitObjects = selectedMovableObjects;
|
||||||
|
|
||||||
var selectedObjectsQuad = getSurroundingQuad(hitObjects);
|
var flipQuad = flipOverOrigin ? new Quad(0, 0, OsuPlayfield.BASE_SIZE.X, OsuPlayfield.BASE_SIZE.Y) : getSurroundingQuad(hitObjects);
|
||||||
|
|
||||||
|
bool didFlip = false;
|
||||||
|
|
||||||
foreach (var h in hitObjects)
|
foreach (var h in hitObjects)
|
||||||
{
|
{
|
||||||
h.Position = GetFlippedPosition(direction, selectedObjectsQuad, h.Position);
|
var flippedPosition = GetFlippedPosition(direction, flipQuad, h.Position);
|
||||||
|
|
||||||
|
if (!Precision.AlmostEquals(flippedPosition, h.Position))
|
||||||
|
{
|
||||||
|
h.Position = flippedPosition;
|
||||||
|
didFlip = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (h is Slider slider)
|
if (h is Slider slider)
|
||||||
{
|
{
|
||||||
|
didFlip = true;
|
||||||
|
|
||||||
foreach (var point in slider.Path.ControlPoints)
|
foreach (var point in slider.Path.ControlPoints)
|
||||||
{
|
{
|
||||||
point.Position = new Vector2(
|
point.Position = new Vector2(
|
||||||
@ -106,7 +117,7 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return didFlip;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool HandleScale(Vector2 scale, Anchor reference)
|
public override bool HandleScale(Vector2 scale, Anchor reference)
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
// 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 osu.Framework.Audio.Track;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
||||||
|
{
|
||||||
|
internal class KiaiFlashingDrawable : BeatSyncedContainer
|
||||||
|
{
|
||||||
|
private readonly Drawable flashingDrawable;
|
||||||
|
|
||||||
|
private const float flash_opacity = 0.3f;
|
||||||
|
|
||||||
|
public KiaiFlashingDrawable(Func<Drawable?> creationFunc)
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
Children = new[]
|
||||||
|
{
|
||||||
|
(creationFunc.Invoke() ?? Empty()).With(d =>
|
||||||
|
{
|
||||||
|
d.Anchor = Anchor.Centre;
|
||||||
|
d.Origin = Anchor.Centre;
|
||||||
|
}),
|
||||||
|
flashingDrawable = (creationFunc.Invoke() ?? Empty()).With(d =>
|
||||||
|
{
|
||||||
|
d.Anchor = Anchor.Centre;
|
||||||
|
d.Origin = Anchor.Centre;
|
||||||
|
d.Alpha = 0;
|
||||||
|
d.Blending = BlendingParameters.Additive;
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes)
|
||||||
|
{
|
||||||
|
if (!effectPoint.KiaiMode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
flashingDrawable
|
||||||
|
.FadeTo(flash_opacity)
|
||||||
|
.Then()
|
||||||
|
.FadeOut(timingPoint.BeatLength * 0.75f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,61 +0,0 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
|
||||||
|
|
||||||
using osu.Framework.Audio.Track;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Framework.Graphics.Sprites;
|
|
||||||
using osu.Framework.Graphics.Textures;
|
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
|
||||||
using osu.Game.Graphics.Containers;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|
||||||
{
|
|
||||||
internal class KiaiFlashingSprite : BeatSyncedContainer
|
|
||||||
{
|
|
||||||
private readonly Sprite mainSprite;
|
|
||||||
private readonly Sprite flashingSprite;
|
|
||||||
|
|
||||||
public Texture Texture
|
|
||||||
{
|
|
||||||
set
|
|
||||||
{
|
|
||||||
mainSprite.Texture = value;
|
|
||||||
flashingSprite.Texture = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private const float flash_opacity = 0.3f;
|
|
||||||
|
|
||||||
public KiaiFlashingSprite()
|
|
||||||
{
|
|
||||||
AutoSizeAxes = Axes.Both;
|
|
||||||
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
mainSprite = new Sprite
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
},
|
|
||||||
flashingSprite = new Sprite
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
Alpha = 0,
|
|
||||||
Blending = BlendingParameters.Additive,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes)
|
|
||||||
{
|
|
||||||
if (!effectPoint.KiaiMode)
|
|
||||||
return;
|
|
||||||
|
|
||||||
flashingSprite
|
|
||||||
.FadeTo(flash_opacity)
|
|
||||||
.Then()
|
|
||||||
.FadeOut(timingPoint.BeatLength * 0.75f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,6 +5,7 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
@ -68,13 +69,11 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
// at this point, any further texture fetches should be correctly using the priority source if the base texture was retrieved using it.
|
// at this point, any further texture fetches should be correctly using the priority source if the base texture was retrieved using it.
|
||||||
// the flow above handles the case where a sliderendcircle.png is retrieved from the skin, but sliderendcircleoverlay.png doesn't exist.
|
// the flow above handles the case where a sliderendcircle.png is retrieved from the skin, but sliderendcircleoverlay.png doesn't exist.
|
||||||
// expected behaviour in this scenario is not showing the overlay, rather than using hitcircleoverlay.png (potentially from the default/fall-through skin).
|
// expected behaviour in this scenario is not showing the overlay, rather than using hitcircleoverlay.png (potentially from the default/fall-through skin).
|
||||||
Texture overlayTexture = getTextureWithFallback("overlay");
|
|
||||||
|
|
||||||
InternalChildren = new[]
|
InternalChildren = new[]
|
||||||
{
|
{
|
||||||
hitCircleSprite = new KiaiFlashingSprite
|
hitCircleSprite = new KiaiFlashingDrawable(() => new Sprite { Texture = baseTexture })
|
||||||
{
|
{
|
||||||
Texture = baseTexture,
|
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
},
|
},
|
||||||
@ -82,9 +81,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Child = hitCircleOverlay = new KiaiFlashingSprite
|
Child = hitCircleOverlay = new KiaiFlashingDrawable(() => getAnimationWithFallback(@"overlay", 1000 / 2d))
|
||||||
{
|
{
|
||||||
Texture = overlayTexture,
|
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
},
|
},
|
||||||
@ -126,6 +124,21 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
|
|
||||||
return tex ?? skin.GetTexture($"hitcircle{name}");
|
return tex ?? skin.GetTexture($"hitcircle{name}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Drawable getAnimationWithFallback(string name, double frameLength)
|
||||||
|
{
|
||||||
|
Drawable animation = null;
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(priorityLookup))
|
||||||
|
{
|
||||||
|
animation = skin.GetAnimation($"{priorityLookup}{name}", true, true, frameLength: frameLength);
|
||||||
|
|
||||||
|
if (!allowFallback)
|
||||||
|
return animation;
|
||||||
|
}
|
||||||
|
|
||||||
|
return animation ?? skin.GetAnimation($"hitcircle{name}", true, true, frameLength: frameLength);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
@ -36,7 +37,9 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
protected override bool HasCustomSteps => true;
|
protected override bool HasCustomSteps => true;
|
||||||
|
|
||||||
protected override TestPlayer CreatePlayer(Ruleset ruleset) => new NonImportingPlayer(false);
|
protected override TestPlayer CreatePlayer(Ruleset ruleset) => new FakeImportingPlayer(false);
|
||||||
|
|
||||||
|
protected new FakeImportingPlayer Player => (FakeImportingPlayer)base.Player;
|
||||||
|
|
||||||
protected override Ruleset CreatePlayerRuleset() => createCustomRuleset?.Invoke() ?? new OsuRuleset();
|
protected override Ruleset CreatePlayerRuleset() => createCustomRuleset?.Invoke() ?? new OsuRuleset();
|
||||||
|
|
||||||
@ -207,6 +210,25 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
AddAssert("ensure failing submission", () => Player.SubmittedScore?.ScoreInfo.Passed == false);
|
AddAssert("ensure failing submission", () => Player.SubmittedScore?.ScoreInfo.Passed == false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSubmissionOnExitDuringImport()
|
||||||
|
{
|
||||||
|
prepareTokenResponse(true);
|
||||||
|
|
||||||
|
createPlayerTest();
|
||||||
|
AddStep("block imports", () => Player.AllowImportCompletion.Wait());
|
||||||
|
|
||||||
|
AddUntilStep("wait for token request", () => Player.TokenCreationRequested);
|
||||||
|
|
||||||
|
addFakeHit();
|
||||||
|
|
||||||
|
AddUntilStep("wait for import to start", () => Player.ScoreImportStarted);
|
||||||
|
|
||||||
|
AddStep("exit", () => Player.Exit());
|
||||||
|
AddStep("allow import to proceed", () => Player.AllowImportCompletion.Release(1));
|
||||||
|
AddAssert("ensure submission", () => Player.SubmittedScore != null && Player.ImportedScore != null);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestNoSubmissionOnLocalBeatmap()
|
public void TestNoSubmissionOnLocalBeatmap()
|
||||||
{
|
{
|
||||||
@ -288,15 +310,26 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private class NonImportingPlayer : TestPlayer
|
protected class FakeImportingPlayer : TestPlayer
|
||||||
{
|
{
|
||||||
public NonImportingPlayer(bool allowPause = true, bool showResults = true, bool pauseOnFocusLost = false)
|
public bool ScoreImportStarted { get; set; }
|
||||||
|
public SemaphoreSlim AllowImportCompletion { get; }
|
||||||
|
public Score ImportedScore { get; private set; }
|
||||||
|
|
||||||
|
public FakeImportingPlayer(bool allowPause = true, bool showResults = true, bool pauseOnFocusLost = false)
|
||||||
: base(allowPause, showResults, pauseOnFocusLost)
|
: base(allowPause, showResults, pauseOnFocusLost)
|
||||||
{
|
{
|
||||||
|
AllowImportCompletion = new SemaphoreSlim(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Task ImportScore(Score score)
|
protected override async Task ImportScore(Score score)
|
||||||
{
|
{
|
||||||
|
ScoreImportStarted = true;
|
||||||
|
|
||||||
|
await AllowImportCompletion.WaitAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
|
ImportedScore = score;
|
||||||
|
|
||||||
// It was discovered that Score members could sometimes be half-populated.
|
// It was discovered that Score members could sometimes be half-populated.
|
||||||
// In particular, the RulesetID property could be set to 0 even on non-osu! maps.
|
// In particular, the RulesetID property could be set to 0 even on non-osu! maps.
|
||||||
// We want to test that the state of that property is consistent in this test.
|
// We want to test that the state of that property is consistent in this test.
|
||||||
@ -311,8 +344,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
// In the above instance, if a ScoreInfo with Ruleset = {mania} and RulesetID = 0 is attached to an EF context,
|
// In the above instance, if a ScoreInfo with Ruleset = {mania} and RulesetID = 0 is attached to an EF context,
|
||||||
// RulesetID WILL BE SILENTLY SET TO THE CORRECT VALUE of 3.
|
// RulesetID WILL BE SILENTLY SET TO THE CORRECT VALUE of 3.
|
||||||
//
|
//
|
||||||
// For the above reasons, importing is disabled in this test.
|
// For the above reasons, actual importing is disabled in this test.
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,8 +53,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
CreateTest(null);
|
CreateTest(null);
|
||||||
AddUntilStep("completion set by processor", () => Player.ScoreProcessor.HasCompleted.Value);
|
AddUntilStep("completion set by processor", () => Player.ScoreProcessor.HasCompleted.Value);
|
||||||
AddStep("skip outro", () => InputManager.Key(osuTK.Input.Key.Space));
|
AddStep("skip outro", () => InputManager.Key(osuTK.Input.Key.Space));
|
||||||
|
AddAssert("player is no longer current screen", () => !Player.IsCurrentScreen());
|
||||||
AddUntilStep("wait for score shown", () => Player.IsScoreShown);
|
AddUntilStep("wait for score shown", () => Player.IsScoreShown);
|
||||||
AddUntilStep("time less than storyboard duration", () => Player.GameplayClockContainer.GameplayClock.CurrentTime < currentStoryboardDuration);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -50,6 +50,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
});
|
});
|
||||||
|
|
||||||
AddUntilStep("wait for load", () => leaderboard.IsLoaded);
|
AddUntilStep("wait for load", () => leaderboard.IsLoaded);
|
||||||
|
AddUntilStep("wait for user population", () => leaderboard.ChildrenOfType<GameplayLeaderboardScore>().Count() == 2);
|
||||||
|
|
||||||
AddStep("add clock sources", () =>
|
AddStep("add clock sources", () =>
|
||||||
{
|
{
|
||||||
|
@ -107,19 +107,31 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
AddUntilStep("is hidden", () => overlay.State.Value == Visibility.Hidden);
|
AddUntilStep("is hidden", () => overlay.State.Value == Visibility.Hidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestCorrectOldContentExpiration()
|
||||||
|
{
|
||||||
|
AddAssert("is visible", () => overlay.State.Value == Visibility.Visible);
|
||||||
|
|
||||||
|
AddStep("show many results", () => fetchFor(Enumerable.Repeat(CreateAPIBeatmapSet(Ruleset.Value), 100).ToArray()));
|
||||||
|
assertAllCardsOfType<BeatmapCardNormal>(100);
|
||||||
|
|
||||||
|
AddStep("show more results", () => fetchFor(Enumerable.Repeat(CreateAPIBeatmapSet(Ruleset.Value), 30).ToArray()));
|
||||||
|
assertAllCardsOfType<BeatmapCardNormal>(30);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestCardSizeSwitching()
|
public void TestCardSizeSwitching()
|
||||||
{
|
{
|
||||||
AddAssert("is visible", () => overlay.State.Value == Visibility.Visible);
|
AddAssert("is visible", () => overlay.State.Value == Visibility.Visible);
|
||||||
|
|
||||||
AddStep("show many results", () => fetchFor(Enumerable.Repeat(CreateAPIBeatmapSet(Ruleset.Value), 100).ToArray()));
|
AddStep("show many results", () => fetchFor(Enumerable.Repeat(CreateAPIBeatmapSet(Ruleset.Value), 100).ToArray()));
|
||||||
assertAllCardsOfType<BeatmapCardNormal>();
|
assertAllCardsOfType<BeatmapCardNormal>(100);
|
||||||
|
|
||||||
setCardSize(BeatmapCardSize.Extra);
|
setCardSize(BeatmapCardSize.Extra);
|
||||||
assertAllCardsOfType<BeatmapCardExtra>();
|
assertAllCardsOfType<BeatmapCardExtra>(100);
|
||||||
|
|
||||||
setCardSize(BeatmapCardSize.Normal);
|
setCardSize(BeatmapCardSize.Normal);
|
||||||
assertAllCardsOfType<BeatmapCardNormal>();
|
assertAllCardsOfType<BeatmapCardNormal>(100);
|
||||||
|
|
||||||
AddStep("fetch for 0 beatmaps", () => fetchFor());
|
AddStep("fetch for 0 beatmaps", () => fetchFor());
|
||||||
AddUntilStep("placeholder shown", () => overlay.ChildrenOfType<BeatmapListingOverlay.NotFoundDrawable>().SingleOrDefault()?.IsPresent == true);
|
AddUntilStep("placeholder shown", () => overlay.ChildrenOfType<BeatmapListingOverlay.NotFoundDrawable>().SingleOrDefault()?.IsPresent == true);
|
||||||
@ -323,13 +335,12 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
|
|
||||||
private void setCardSize(BeatmapCardSize cardSize) => AddStep($"set card size to {cardSize}", () => overlay.ChildrenOfType<BeatmapListingCardSizeTabControl>().Single().Current.Value = cardSize);
|
private void setCardSize(BeatmapCardSize cardSize) => AddStep($"set card size to {cardSize}", () => overlay.ChildrenOfType<BeatmapListingCardSizeTabControl>().Single().Current.Value = cardSize);
|
||||||
|
|
||||||
private void assertAllCardsOfType<T>()
|
private void assertAllCardsOfType<T>(int expectedCount)
|
||||||
where T : BeatmapCard =>
|
where T : BeatmapCard =>
|
||||||
AddUntilStep($"all loaded beatmap cards are {typeof(T)}", () =>
|
AddUntilStep($"all loaded beatmap cards are {typeof(T)}", () =>
|
||||||
{
|
{
|
||||||
int loadedCorrectCount = this.ChildrenOfType<BeatmapCard>().Count(card => card.IsLoaded && card.GetType() == typeof(T));
|
int loadedCorrectCount = this.ChildrenOfType<BeatmapCard>().Count(card => card.IsLoaded && card.GetType() == typeof(T));
|
||||||
int totalCount = this.ChildrenOfType<BeatmapCard>().Count();
|
return loadedCorrectCount > 0 && loadedCorrectCount == expectedCount;
|
||||||
return loadedCorrectCount > 0 && loadedCorrectCount == totalCount;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
79
osu.Game.Tests/Visual/UserInterface/TestScenePageSelector.cs
Normal file
79
osu.Game.Tests/Visual/UserInterface/TestScenePageSelector.cs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
// 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.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Graphics.UserInterface.PageSelector;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.UserInterface
|
||||||
|
{
|
||||||
|
public class TestScenePageSelector : OsuTestScene
|
||||||
|
{
|
||||||
|
[Cached]
|
||||||
|
private OverlayColourProvider provider { get; } = new OverlayColourProvider(OverlayColourScheme.Green);
|
||||||
|
|
||||||
|
private readonly PageSelector pageSelector;
|
||||||
|
|
||||||
|
public TestScenePageSelector()
|
||||||
|
{
|
||||||
|
AddRange(new Drawable[]
|
||||||
|
{
|
||||||
|
pageSelector = new PageSelector
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestOmittedPages()
|
||||||
|
{
|
||||||
|
setAvailablePages(100);
|
||||||
|
|
||||||
|
selectPageIndex(0);
|
||||||
|
checkVisiblePageNumbers(new[] { 1, 2, 3, 100 });
|
||||||
|
|
||||||
|
selectPageIndex(6);
|
||||||
|
checkVisiblePageNumbers(new[] { 1, 5, 6, 7, 8, 9, 100 });
|
||||||
|
|
||||||
|
selectPageIndex(49);
|
||||||
|
checkVisiblePageNumbers(new[] { 1, 48, 49, 50, 51, 52, 100 });
|
||||||
|
|
||||||
|
selectPageIndex(99);
|
||||||
|
checkVisiblePageNumbers(new[] { 1, 98, 99, 100 });
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestResetCurrentPage()
|
||||||
|
{
|
||||||
|
setAvailablePages(10);
|
||||||
|
selectPageIndex(6);
|
||||||
|
setAvailablePages(11);
|
||||||
|
AddAssert("Page 1 is current", () => pageSelector.CurrentPage.Value == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestOutOfBoundsSelection()
|
||||||
|
{
|
||||||
|
setAvailablePages(10);
|
||||||
|
selectPageIndex(11);
|
||||||
|
AddAssert("Page 10 is current", () => pageSelector.CurrentPage.Value == pageSelector.AvailablePages.Value - 1);
|
||||||
|
|
||||||
|
selectPageIndex(-1);
|
||||||
|
AddAssert("Page 1 is current", () => pageSelector.CurrentPage.Value == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkVisiblePageNumbers(int[] expected) => AddAssert($"Sequence is {string.Join(',', expected.Select(i => i.ToString()))}", () => pageSelector.ChildrenOfType<PageSelectorPageButton>().Select(p => p.PageNumber).SequenceEqual(expected));
|
||||||
|
|
||||||
|
private void selectPageIndex(int pageIndex) =>
|
||||||
|
AddStep($"Select page {pageIndex}", () => pageSelector.CurrentPage.Value = pageIndex);
|
||||||
|
|
||||||
|
private void setAvailablePages(int availablePages) =>
|
||||||
|
AddStep($"Set available pages to {availablePages}", () => pageSelector.AvailablePages.Value = availablePages);
|
||||||
|
}
|
||||||
|
}
|
@ -3,16 +3,13 @@
|
|||||||
|
|
||||||
#nullable enable
|
#nullable enable
|
||||||
|
|
||||||
using System;
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Effects;
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Input.Events;
|
|
||||||
using osu.Framework.Threading;
|
using osu.Framework.Threading;
|
||||||
using osu.Framework.Utils;
|
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -156,54 +153,5 @@ namespace osu.Game.Beatmaps.Drawables.Cards
|
|||||||
Hollow = true,
|
Hollow = true,
|
||||||
}, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
|
}, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ExpandedContentScrollContainer : OsuScrollContainer
|
|
||||||
{
|
|
||||||
public ExpandedContentScrollContainer()
|
|
||||||
{
|
|
||||||
ScrollbarVisible = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Update()
|
|
||||||
{
|
|
||||||
base.Update();
|
|
||||||
|
|
||||||
Height = Math.Min(Content.DrawHeight, 400);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool allowScroll => !Precision.AlmostEquals(DrawSize, Content.DrawSize);
|
|
||||||
|
|
||||||
protected override bool OnDragStart(DragStartEvent e)
|
|
||||||
{
|
|
||||||
if (!allowScroll)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return base.OnDragStart(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnDrag(DragEvent e)
|
|
||||||
{
|
|
||||||
if (!allowScroll)
|
|
||||||
return;
|
|
||||||
|
|
||||||
base.OnDrag(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnDragEnd(DragEndEvent e)
|
|
||||||
{
|
|
||||||
if (!allowScroll)
|
|
||||||
return;
|
|
||||||
|
|
||||||
base.OnDragEnd(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool OnScroll(ScrollEvent e)
|
|
||||||
{
|
|
||||||
if (!allowScroll)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return base.OnScroll(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,61 @@
|
|||||||
|
// 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 osu.Framework.Input.Events;
|
||||||
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
|
||||||
|
namespace osu.Game.Beatmaps.Drawables.Cards
|
||||||
|
{
|
||||||
|
public class ExpandedContentScrollContainer : OsuScrollContainer
|
||||||
|
{
|
||||||
|
public const float HEIGHT = 200;
|
||||||
|
|
||||||
|
public ExpandedContentScrollContainer()
|
||||||
|
{
|
||||||
|
ScrollbarVisible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
Height = Math.Min(Content.DrawHeight, HEIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool allowScroll => !Precision.AlmostEquals(DrawSize, Content.DrawSize);
|
||||||
|
|
||||||
|
protected override bool OnDragStart(DragStartEvent e)
|
||||||
|
{
|
||||||
|
if (!allowScroll)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return base.OnDragStart(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnDrag(DragEvent e)
|
||||||
|
{
|
||||||
|
if (!allowScroll)
|
||||||
|
return;
|
||||||
|
|
||||||
|
base.OnDrag(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnDragEnd(DragEndEvent e)
|
||||||
|
{
|
||||||
|
if (!allowScroll)
|
||||||
|
return;
|
||||||
|
|
||||||
|
base.OnDragEnd(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnScroll(ScrollEvent e)
|
||||||
|
{
|
||||||
|
if (!allowScroll)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return base.OnScroll(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -98,6 +98,8 @@ namespace osu.Game.Configuration
|
|||||||
SetDefault(OsuSetting.MenuParallax, true);
|
SetDefault(OsuSetting.MenuParallax, true);
|
||||||
|
|
||||||
// Gameplay
|
// Gameplay
|
||||||
|
SetDefault(OsuSetting.PositionalHitsounds, true); // replaced by level setting below, can be removed 20220703.
|
||||||
|
SetDefault(OsuSetting.PositionalHitsoundsLevel, 0.2f, 0, 1);
|
||||||
SetDefault(OsuSetting.DimLevel, 0.8, 0, 1, 0.01);
|
SetDefault(OsuSetting.DimLevel, 0.8, 0, 1, 0.01);
|
||||||
SetDefault(OsuSetting.BlurLevel, 0, 0, 1, 0.01);
|
SetDefault(OsuSetting.BlurLevel, 0, 0, 1, 0.01);
|
||||||
SetDefault(OsuSetting.LightenDuringBreaks, true);
|
SetDefault(OsuSetting.LightenDuringBreaks, true);
|
||||||
@ -109,7 +111,6 @@ namespace osu.Game.Configuration
|
|||||||
SetDefault(OsuSetting.ShowHealthDisplayWhenCantFail, true);
|
SetDefault(OsuSetting.ShowHealthDisplayWhenCantFail, true);
|
||||||
SetDefault(OsuSetting.FadePlayfieldWhenHealthLow, true);
|
SetDefault(OsuSetting.FadePlayfieldWhenHealthLow, true);
|
||||||
SetDefault(OsuSetting.KeyOverlay, false);
|
SetDefault(OsuSetting.KeyOverlay, false);
|
||||||
SetDefault(OsuSetting.PositionalHitSounds, true);
|
|
||||||
SetDefault(OsuSetting.AlwaysPlayFirstComboBreak, true);
|
SetDefault(OsuSetting.AlwaysPlayFirstComboBreak, true);
|
||||||
|
|
||||||
SetDefault(OsuSetting.FloatingComments, false);
|
SetDefault(OsuSetting.FloatingComments, false);
|
||||||
@ -175,9 +176,11 @@ namespace osu.Game.Configuration
|
|||||||
|
|
||||||
int combined = (year * 10000) + monthDay;
|
int combined = (year * 10000) + monthDay;
|
||||||
|
|
||||||
if (combined < 20210413)
|
if (combined < 20220103)
|
||||||
{
|
{
|
||||||
SetValue(OsuSetting.EditorWaveformOpacity, 0.25f);
|
var positionalHitsoundsEnabled = GetBindable<bool>(OsuSetting.PositionalHitsounds);
|
||||||
|
if (!positionalHitsoundsEnabled.Value)
|
||||||
|
SetValue(OsuSetting.PositionalHitsoundsLevel, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,7 +259,8 @@ namespace osu.Game.Configuration
|
|||||||
LightenDuringBreaks,
|
LightenDuringBreaks,
|
||||||
ShowStoryboard,
|
ShowStoryboard,
|
||||||
KeyOverlay,
|
KeyOverlay,
|
||||||
PositionalHitSounds,
|
PositionalHitsounds,
|
||||||
|
PositionalHitsoundsLevel,
|
||||||
AlwaysPlayFirstComboBreak,
|
AlwaysPlayFirstComboBreak,
|
||||||
FloatingComments,
|
FloatingComments,
|
||||||
HUDVisibilityMode,
|
HUDVisibilityMode,
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Globalization;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
using osu.Framework.IO.Network;
|
using osu.Framework.IO.Network;
|
||||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
using osu.Game.Online.API.Requests;
|
using osu.Game.Online.API.Requests;
|
||||||
@ -16,7 +18,7 @@ namespace osu.Game.Extensions
|
|||||||
{
|
{
|
||||||
cursor?.Properties.ForEach(x =>
|
cursor?.Properties.ForEach(x =>
|
||||||
{
|
{
|
||||||
webRequest.AddParameter("cursor[" + x.Key + "]", x.Value.ToString());
|
webRequest.AddParameter("cursor[" + x.Key + "]", (x.Value as JValue)?.ToString(CultureInfo.InvariantCulture) ?? x.Value.ToString());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
33
osu.Game/Graphics/UserInterface/PageSelector/PageEllipsis.cs
Normal file
33
osu.Game/Graphics/UserInterface/PageSelector/PageEllipsis.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 osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
|
||||||
|
namespace osu.Game.Graphics.UserInterface.PageSelector
|
||||||
|
{
|
||||||
|
internal class PageEllipsis : CompositeDrawable
|
||||||
|
{
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OverlayColourProvider colourProvider)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Y;
|
||||||
|
AutoSizeAxes = Axes.X;
|
||||||
|
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold),
|
||||||
|
Text = "...",
|
||||||
|
Colour = colourProvider.Light3,
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
102
osu.Game/Graphics/UserInterface/PageSelector/PageSelector.cs
Normal file
102
osu.Game/Graphics/UserInterface/PageSelector/PageSelector.cs
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
// 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 osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
|
||||||
|
namespace osu.Game.Graphics.UserInterface.PageSelector
|
||||||
|
{
|
||||||
|
public class PageSelector : CompositeDrawable
|
||||||
|
{
|
||||||
|
public readonly BindableInt CurrentPage = new BindableInt { MinValue = 0, };
|
||||||
|
|
||||||
|
public readonly BindableInt AvailablePages = new BindableInt(1) { MinValue = 1, };
|
||||||
|
|
||||||
|
private readonly FillFlowContainer itemsFlow;
|
||||||
|
|
||||||
|
private readonly PageSelectorPrevNextButton previousPageButton;
|
||||||
|
private readonly PageSelectorPrevNextButton nextPageButton;
|
||||||
|
|
||||||
|
public PageSelector()
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
InternalChild = new FillFlowContainer
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
previousPageButton = new PageSelectorPrevNextButton(false, "prev")
|
||||||
|
{
|
||||||
|
Action = () => CurrentPage.Value -= 1,
|
||||||
|
},
|
||||||
|
itemsFlow = new FillFlowContainer
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
},
|
||||||
|
nextPageButton = new PageSelectorPrevNextButton(true, "next")
|
||||||
|
{
|
||||||
|
Action = () => CurrentPage.Value += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
CurrentPage.BindValueChanged(_ => Scheduler.AddOnce(redraw));
|
||||||
|
AvailablePages.BindValueChanged(_ =>
|
||||||
|
{
|
||||||
|
CurrentPage.Value = 0;
|
||||||
|
|
||||||
|
// AddOnce as the reset of CurrentPage may also trigger a redraw.
|
||||||
|
Scheduler.AddOnce(redraw);
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void redraw()
|
||||||
|
{
|
||||||
|
if (CurrentPage.Value >= AvailablePages.Value)
|
||||||
|
{
|
||||||
|
CurrentPage.Value = AvailablePages.Value - 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
previousPageButton.Enabled.Value = CurrentPage.Value != 0;
|
||||||
|
nextPageButton.Enabled.Value = CurrentPage.Value < AvailablePages.Value - 1;
|
||||||
|
|
||||||
|
itemsFlow.Clear();
|
||||||
|
|
||||||
|
int totalPages = AvailablePages.Value;
|
||||||
|
bool lastWasEllipsis = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < totalPages; i++)
|
||||||
|
{
|
||||||
|
int pageIndex = i;
|
||||||
|
|
||||||
|
bool shouldShowPage = pageIndex == 0 || pageIndex == totalPages - 1 || Math.Abs(pageIndex - CurrentPage.Value) <= 2;
|
||||||
|
|
||||||
|
if (shouldShowPage)
|
||||||
|
{
|
||||||
|
lastWasEllipsis = false;
|
||||||
|
itemsFlow.Add(new PageSelectorPageButton(pageIndex + 1)
|
||||||
|
{
|
||||||
|
Action = () => CurrentPage.Value = pageIndex,
|
||||||
|
Selected = CurrentPage.Value == pageIndex,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (!lastWasEllipsis)
|
||||||
|
{
|
||||||
|
lastWasEllipsis = true;
|
||||||
|
itemsFlow.Add(new PageEllipsis());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
// 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.Containers;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
|
||||||
|
namespace osu.Game.Graphics.UserInterface.PageSelector
|
||||||
|
{
|
||||||
|
public abstract class PageSelectorButton : OsuClickableContainer
|
||||||
|
{
|
||||||
|
protected const int DURATION = 200;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
protected OverlayColourProvider ColourProvider { get; private set; }
|
||||||
|
|
||||||
|
protected Box Background;
|
||||||
|
|
||||||
|
protected PageSelectorButton()
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.X;
|
||||||
|
Height = 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
Add(new CircularContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
AutoSizeAxes = Axes.X,
|
||||||
|
Masking = true,
|
||||||
|
Children = new[]
|
||||||
|
{
|
||||||
|
Background = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both
|
||||||
|
},
|
||||||
|
CreateContent().With(content =>
|
||||||
|
{
|
||||||
|
content.Anchor = Anchor.Centre;
|
||||||
|
content.Origin = Anchor.Centre;
|
||||||
|
content.Margin = new MarginPadding { Horizontal = 10 };
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[NotNull]
|
||||||
|
protected abstract Drawable CreateContent();
|
||||||
|
|
||||||
|
protected override bool OnHover(HoverEvent e)
|
||||||
|
{
|
||||||
|
UpdateHoverState();
|
||||||
|
return base.OnHover(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnHoverLost(HoverLostEvent e)
|
||||||
|
{
|
||||||
|
base.OnHoverLost(e);
|
||||||
|
UpdateHoverState();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void UpdateHoverState();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
// 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.Bindables;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
|
||||||
|
namespace osu.Game.Graphics.UserInterface.PageSelector
|
||||||
|
{
|
||||||
|
public class PageSelectorPageButton : PageSelectorButton
|
||||||
|
{
|
||||||
|
private readonly BindableBool selected = new BindableBool();
|
||||||
|
|
||||||
|
public bool Selected
|
||||||
|
{
|
||||||
|
set => selected.Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int PageNumber { get; }
|
||||||
|
|
||||||
|
private OsuSpriteText text;
|
||||||
|
|
||||||
|
public PageSelectorPageButton(int pageNumber)
|
||||||
|
{
|
||||||
|
PageNumber = pageNumber;
|
||||||
|
|
||||||
|
Action = () =>
|
||||||
|
{
|
||||||
|
if (!selected.Value)
|
||||||
|
selected.Value = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Drawable CreateContent() => text = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold),
|
||||||
|
Text = PageNumber.ToString(),
|
||||||
|
};
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
Background.Colour = ColourProvider.Highlight1;
|
||||||
|
Background.Alpha = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
selected.BindValueChanged(onSelectedChanged, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onSelectedChanged(ValueChangedEvent<bool> selected)
|
||||||
|
{
|
||||||
|
Background.FadeTo(selected.NewValue ? 1 : 0, DURATION, Easing.OutQuint);
|
||||||
|
|
||||||
|
text.FadeColour(selected.NewValue ? ColourProvider.Dark4 : ColourProvider.Light3, DURATION, Easing.OutQuint);
|
||||||
|
text.Font = text.Font.With(weight: IsHovered ? FontWeight.SemiBold : FontWeight.Regular);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void UpdateHoverState()
|
||||||
|
{
|
||||||
|
if (selected.Value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
text.FadeColour(IsHovered ? ColourProvider.Light2 : ColourProvider.Light1, DURATION, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Graphics.UserInterface.PageSelector
|
||||||
|
{
|
||||||
|
public class PageSelectorPrevNextButton : PageSelectorButton
|
||||||
|
{
|
||||||
|
private readonly bool rightAligned;
|
||||||
|
private readonly string text;
|
||||||
|
|
||||||
|
private SpriteIcon icon;
|
||||||
|
private OsuSpriteText name;
|
||||||
|
|
||||||
|
public PageSelectorPrevNextButton(bool rightAligned, string text)
|
||||||
|
{
|
||||||
|
this.rightAligned = rightAligned;
|
||||||
|
this.text = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Drawable CreateContent() => new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
AutoSizeAxes = Axes.X,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Spacing = new Vector2(3, 0),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
name = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Font = OsuFont.GetFont(size: 12),
|
||||||
|
Anchor = rightAligned ? Anchor.CentreLeft : Anchor.CentreRight,
|
||||||
|
Origin = rightAligned ? Anchor.CentreLeft : Anchor.CentreRight,
|
||||||
|
Text = text.ToUpper(),
|
||||||
|
},
|
||||||
|
icon = new SpriteIcon
|
||||||
|
{
|
||||||
|
Icon = rightAligned ? FontAwesome.Solid.ChevronRight : FontAwesome.Solid.ChevronLeft,
|
||||||
|
Size = new Vector2(8),
|
||||||
|
Anchor = rightAligned ? Anchor.CentreLeft : Anchor.CentreRight,
|
||||||
|
Origin = rightAligned ? Anchor.CentreLeft : Anchor.CentreRight,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
Background.Colour = ColourProvider.Dark4;
|
||||||
|
name.Colour = icon.Colour = ColourProvider.Light1;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
Enabled.BindValueChanged(enabled => Background.FadeTo(enabled.NewValue ? 1 : 0.5f, DURATION), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void UpdateHoverState() =>
|
||||||
|
Background.FadeColour(IsHovered ? ColourProvider.Dark3 : ColourProvider.Dark4, DURATION, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
}
|
@ -32,7 +32,18 @@ namespace osu.Game.IO.Archives
|
|||||||
|
|
||||||
public abstract IEnumerable<string> Filenames { get; }
|
public abstract IEnumerable<string> Filenames { get; }
|
||||||
|
|
||||||
public virtual byte[] Get(string name) => GetAsync(name).Result;
|
public virtual byte[] Get(string name)
|
||||||
|
{
|
||||||
|
using (Stream input = GetStream(name))
|
||||||
|
{
|
||||||
|
if (input == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
byte[] buffer = new byte[input.Length];
|
||||||
|
input.Read(buffer);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<byte[]> GetAsync(string name, CancellationToken cancellationToken = default)
|
public async Task<byte[]> GetAsync(string name, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
|
@ -77,6 +77,8 @@ namespace osu.Game.Input.Bindings
|
|||||||
new KeyBinding(new[] { InputKey.K }, GlobalAction.EditorNudgeRight),
|
new KeyBinding(new[] { InputKey.K }, GlobalAction.EditorNudgeRight),
|
||||||
new KeyBinding(new[] { InputKey.G }, GlobalAction.EditorCycleGridDisplayMode),
|
new KeyBinding(new[] { InputKey.G }, GlobalAction.EditorCycleGridDisplayMode),
|
||||||
new KeyBinding(new[] { InputKey.F5 }, GlobalAction.EditorTestGameplay),
|
new KeyBinding(new[] { InputKey.F5 }, GlobalAction.EditorTestGameplay),
|
||||||
|
new KeyBinding(new[] { InputKey.Control, InputKey.H }, GlobalAction.EditorFlipHorizontally),
|
||||||
|
new KeyBinding(new[] { InputKey.Control, InputKey.J }, GlobalAction.EditorFlipVertically),
|
||||||
};
|
};
|
||||||
|
|
||||||
public IEnumerable<KeyBinding> InGameKeyBindings => new[]
|
public IEnumerable<KeyBinding> InGameKeyBindings => new[]
|
||||||
@ -292,6 +294,12 @@ namespace osu.Game.Input.Bindings
|
|||||||
EditorCycleGridDisplayMode,
|
EditorCycleGridDisplayMode,
|
||||||
|
|
||||||
[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorTestGameplay))]
|
[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorTestGameplay))]
|
||||||
EditorTestGameplay
|
EditorTestGameplay,
|
||||||
|
|
||||||
|
[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorFlipHorizontally))]
|
||||||
|
EditorFlipHorizontally,
|
||||||
|
|
||||||
|
[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorFlipVertically))]
|
||||||
|
EditorFlipVertically,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
|
using osu.Framework.Platform;
|
||||||
using osu.Game.Input.Bindings;
|
using osu.Game.Input.Bindings;
|
||||||
|
|
||||||
namespace osu.Game.Input
|
namespace osu.Game.Input
|
||||||
@ -63,8 +65,17 @@ namespace osu.Game.Input
|
|||||||
|
|
||||||
public void OnReleased(KeyBindingReleaseEvent<GlobalAction> e) => updateLastInteractionTime();
|
public void OnReleased(KeyBindingReleaseEvent<GlobalAction> e) => updateLastInteractionTime();
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private GameHost host { get; set; }
|
||||||
|
|
||||||
protected override bool Handle(UIEvent e)
|
protected override bool Handle(UIEvent e)
|
||||||
{
|
{
|
||||||
|
// Even when not active, `MouseMoveEvent`s will arrive.
|
||||||
|
// We don't want these to trigger a non-idle state as it's quite often the user interacting
|
||||||
|
// with other windows while osu! is in the background.
|
||||||
|
if (!host.IsActive.Value)
|
||||||
|
return base.Handle(e);
|
||||||
|
|
||||||
switch (e)
|
switch (e)
|
||||||
{
|
{
|
||||||
case KeyDownEvent _:
|
case KeyDownEvent _:
|
||||||
|
@ -32,6 +32,11 @@ namespace osu.Game.Localisation
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// "Master"
|
/// "Master"
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
public static LocalisableString PositionalLevel => new TranslatableString(getKey(@"positional_hitsound_audio_level"), @"Hitsound stereo separation");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Level"
|
||||||
|
/// </summary>
|
||||||
public static LocalisableString MasterVolume => new TranslatableString(getKey(@"master_volume"), @"Master");
|
public static LocalisableString MasterVolume => new TranslatableString(getKey(@"master_volume"), @"Master");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -84,11 +84,6 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString AlwaysShowKeyOverlay => new TranslatableString(getKey(@"key_overlay"), @"Always show key overlay");
|
public static LocalisableString AlwaysShowKeyOverlay => new TranslatableString(getKey(@"key_overlay"), @"Always show key overlay");
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// "Positional hitsounds"
|
|
||||||
/// </summary>
|
|
||||||
public static LocalisableString PositionalHitsounds => new TranslatableString(getKey(@"positional_hitsounds"), @"Positional hitsounds");
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// "Always play first combo break sound"
|
/// "Always play first combo break sound"
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -229,6 +229,16 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString EditorNudgeRight => new TranslatableString(getKey(@"editor_nudge_right"), @"Nudge selection right");
|
public static LocalisableString EditorNudgeRight => new TranslatableString(getKey(@"editor_nudge_right"), @"Nudge selection right");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Flip selection horizontally"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString EditorFlipHorizontally => new TranslatableString(getKey(@"editor_flip_horizontally"), @"Flip selection horizontally");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Flip selection vertically"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString EditorFlipVertically => new TranslatableString(getKey(@"editor_flip_vertically"), @"Flip selection vertically");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// "Toggle skin editor"
|
/// "Toggle skin editor"
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -9,6 +9,7 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
|
using osu.Game.Input;
|
||||||
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;
|
||||||
@ -67,11 +68,34 @@ namespace osu.Game.Online.Chat
|
|||||||
|
|
||||||
public readonly BindableBool HighPollRate = new BindableBool();
|
public readonly BindableBool HighPollRate = new BindableBool();
|
||||||
|
|
||||||
|
private readonly IBindable<bool> isIdle = new BindableBool();
|
||||||
|
|
||||||
public ChannelManager()
|
public ChannelManager()
|
||||||
{
|
{
|
||||||
CurrentChannel.ValueChanged += currentChannelChanged;
|
CurrentChannel.ValueChanged += currentChannelChanged;
|
||||||
|
}
|
||||||
|
|
||||||
HighPollRate.BindValueChanged(enabled => TimeBetweenPolls.Value = enabled.NewValue ? 1000 : 6000, true);
|
[BackgroundDependencyLoader(permitNulls: true)]
|
||||||
|
private void load(IdleTracker idleTracker)
|
||||||
|
{
|
||||||
|
HighPollRate.BindValueChanged(updatePollRate);
|
||||||
|
isIdle.BindValueChanged(updatePollRate, true);
|
||||||
|
|
||||||
|
if (idleTracker != null)
|
||||||
|
isIdle.BindTo(idleTracker.IsIdle);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updatePollRate(ValueChangedEvent<bool> valueChangedEvent)
|
||||||
|
{
|
||||||
|
// Polling will eventually be replaced with websocket, but let's avoid doing these background operations as much as possible for now.
|
||||||
|
// The only loss will be delayed PM/message highlight notifications.
|
||||||
|
|
||||||
|
if (HighPollRate.Value)
|
||||||
|
TimeBetweenPolls.Value = 1000;
|
||||||
|
else if (!isIdle.Value)
|
||||||
|
TimeBetweenPolls.Value = 60000;
|
||||||
|
else
|
||||||
|
TimeBetweenPolls.Value = 600000;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -79,7 +79,6 @@ namespace osu.Game.Overlays
|
|||||||
Padding = new MarginPadding { Horizontal = 20 },
|
Padding = new MarginPadding { Horizontal = 20 },
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
foundContent = new FillFlowContainer<BeatmapCard>(),
|
|
||||||
notFoundContent = new NotFoundDrawable(),
|
notFoundContent = new NotFoundDrawable(),
|
||||||
supporterRequiredContent = new SupporterRequiredDrawable(),
|
supporterRequiredContent = new SupporterRequiredDrawable(),
|
||||||
}
|
}
|
||||||
@ -140,7 +139,7 @@ namespace osu.Game.Overlays
|
|||||||
if (searchResult.Type == BeatmapListingFilterControl.SearchResultType.SupporterOnlyFilters)
|
if (searchResult.Type == BeatmapListingFilterControl.SearchResultType.SupporterOnlyFilters)
|
||||||
{
|
{
|
||||||
supporterRequiredContent.UpdateText(searchResult.SupporterOnlyFiltersUsed);
|
supporterRequiredContent.UpdateText(searchResult.SupporterOnlyFiltersUsed);
|
||||||
addContentToPlaceholder(supporterRequiredContent);
|
addContentToResultsArea(supporterRequiredContent);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,13 +150,13 @@ namespace osu.Game.Overlays
|
|||||||
//No matches case
|
//No matches case
|
||||||
if (!newCards.Any())
|
if (!newCards.Any())
|
||||||
{
|
{
|
||||||
addContentToPlaceholder(notFoundContent);
|
addContentToResultsArea(notFoundContent);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var content = createCardContainerFor(newCards);
|
var content = createCardContainerFor(newCards);
|
||||||
|
|
||||||
panelLoadTask = LoadComponentAsync(foundContent = content, addContentToPlaceholder, (cancellationToken = new CancellationTokenSource()).Token);
|
panelLoadTask = LoadComponentAsync(foundContent = content, addContentToResultsArea, (cancellationToken = new CancellationTokenSource()).Token);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -186,13 +185,17 @@ namespace osu.Game.Overlays
|
|||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
Spacing = new Vector2(10),
|
Spacing = new Vector2(10),
|
||||||
Alpha = 0,
|
Alpha = 0,
|
||||||
Margin = new MarginPadding { Vertical = 15 },
|
Margin = new MarginPadding
|
||||||
|
{
|
||||||
|
Vertical = 15,
|
||||||
|
Bottom = ExpandedContentScrollContainer.HEIGHT
|
||||||
|
},
|
||||||
ChildrenEnumerable = newCards
|
ChildrenEnumerable = newCards
|
||||||
};
|
};
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addContentToPlaceholder(Drawable content)
|
private void addContentToResultsArea(Drawable content)
|
||||||
{
|
{
|
||||||
Loading.Hide();
|
Loading.Hide();
|
||||||
lastFetchDisplayedTime = Time.Current;
|
lastFetchDisplayedTime = Time.Current;
|
||||||
@ -204,37 +207,27 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
if (lastContent != null)
|
if (lastContent != null)
|
||||||
{
|
{
|
||||||
lastContent.FadeOut(100, Easing.OutQuint);
|
lastContent.FadeOut();
|
||||||
|
if (!isPlaceholderContent(lastContent))
|
||||||
// Consider the case when the new content is smaller than the last content.
|
lastContent.Expire();
|
||||||
// If the auto-size computation is delayed until fade out completes, the background remain high for too long making the resulting transition to the smaller height look weird.
|
|
||||||
// At the same time, if the last content's height is bypassed immediately, there is a period where the new content is at Alpha = 0 when the auto-sized height will be 0.
|
|
||||||
// To resolve both of these issues, the bypass is delayed until a point when the content transitions (fade-in and fade-out) overlap and it looks good to do so.
|
|
||||||
var sequence = lastContent.Delay(25).Schedule(() => lastContent.BypassAutoSizeAxes = Axes.Y);
|
|
||||||
|
|
||||||
if (lastContent == foundContent)
|
|
||||||
{
|
|
||||||
sequence.Then().Schedule(() =>
|
|
||||||
{
|
|
||||||
foundContent.Expire();
|
|
||||||
foundContent = null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!content.IsAlive)
|
if (!content.IsAlive)
|
||||||
panelTarget.Add(content);
|
panelTarget.Add(content);
|
||||||
|
|
||||||
content.FadeInFromZero(200, Easing.OutQuint);
|
content.FadeInFromZero();
|
||||||
currentContent = content;
|
currentContent = content;
|
||||||
// currentContent may be one of the placeholders, and still have BypassAutoSizeAxes set to Y from the last fade-out.
|
|
||||||
// restore to the initial state.
|
|
||||||
currentContent.BypassAutoSizeAxes = Axes.None;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether <paramref name="drawable"/> is a static placeholder reused multiple times by this overlay.
|
||||||
|
/// </summary>
|
||||||
|
private bool isPlaceholderContent(Drawable drawable)
|
||||||
|
=> drawable == notFoundContent || drawable == supporterRequiredContent;
|
||||||
|
|
||||||
private void onCardSizeChanged()
|
private void onCardSizeChanged()
|
||||||
{
|
{
|
||||||
if (foundContent == null || !foundContent.Any())
|
if (foundContent?.IsAlive != true || !foundContent.Any())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Loading.Show();
|
Loading.Show();
|
||||||
@ -259,10 +252,6 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
public class NotFoundDrawable : CompositeDrawable
|
public class NotFoundDrawable : CompositeDrawable
|
||||||
{
|
{
|
||||||
// required for scheduled tasks to complete correctly
|
|
||||||
// (see `addContentToPlaceholder()` and the scheduled `BypassAutoSizeAxes` set during fade-out in outer class above)
|
|
||||||
public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks;
|
|
||||||
|
|
||||||
public NotFoundDrawable()
|
public NotFoundDrawable()
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
@ -307,10 +296,6 @@ namespace osu.Game.Overlays
|
|||||||
// (https://github.com/ppy/osu-framework/issues/4530)
|
// (https://github.com/ppy/osu-framework/issues/4530)
|
||||||
public class SupporterRequiredDrawable : CompositeDrawable
|
public class SupporterRequiredDrawable : CompositeDrawable
|
||||||
{
|
{
|
||||||
// required for scheduled tasks to complete correctly
|
|
||||||
// (see `addContentToPlaceholder()` and the scheduled `BypassAutoSizeAxes` set during fade-out in outer class above)
|
|
||||||
public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks;
|
|
||||||
|
|
||||||
private LinkFlowContainer supporterRequiredText;
|
private LinkFlowContainer supporterRequiredText;
|
||||||
|
|
||||||
public SupporterRequiredDrawable()
|
public SupporterRequiredDrawable()
|
||||||
|
@ -140,6 +140,7 @@ namespace osu.Game.Overlays.Rankings
|
|||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Margin = new MarginPadding { Bottom = ExpandedContentScrollContainer.HEIGHT },
|
||||||
Spacing = new Vector2(10),
|
Spacing = new Vector2(10),
|
||||||
Children = response.BeatmapSets.Select(b => new BeatmapCardNormal(b)
|
Children = response.BeatmapSets.Select(b => new BeatmapCardNormal(b)
|
||||||
{
|
{
|
||||||
|
@ -14,20 +14,23 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
|
|||||||
protected override LocalisableString Header => GameplaySettingsStrings.AudioHeader;
|
protected override LocalisableString Header => GameplaySettingsStrings.AudioHeader;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuConfigManager config)
|
private void load(OsuConfigManager config, OsuConfigManager osuConfig)
|
||||||
{
|
{
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new SettingsCheckbox
|
new SettingsSlider<float>
|
||||||
{
|
{
|
||||||
LabelText = GameplaySettingsStrings.PositionalHitsounds,
|
LabelText = AudioSettingsStrings.PositionalLevel,
|
||||||
Current = config.GetBindable<bool>(OsuSetting.PositionalHitSounds)
|
Keywords = new[] { @"positional", @"balance" },
|
||||||
|
Current = osuConfig.GetBindable<float>(OsuSetting.PositionalHitsoundsLevel),
|
||||||
|
KeyboardStep = 0.01f,
|
||||||
|
DisplayAsPercentage = true
|
||||||
},
|
},
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = GameplaySettingsStrings.AlwaysPlayFirstComboBreak,
|
LabelText = GameplaySettingsStrings.AlwaysPlayFirstComboBreak,
|
||||||
Current = config.GetBindable<bool>(OsuSetting.AlwaysPlayFirstComboBreak)
|
Current = config.GetBindable<bool>(OsuSetting.AlwaysPlayFirstComboBreak)
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,6 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
Name = "Content",
|
Name = "Content",
|
||||||
Padding = new MarginPadding { Left = toolbar_width },
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
|
@ -123,9 +123,9 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
|
|
||||||
public readonly Bindable<double> StartTimeBindable = new Bindable<double>();
|
public readonly Bindable<double> StartTimeBindable = new Bindable<double>();
|
||||||
private readonly BindableList<HitSampleInfo> samplesBindable = new BindableList<HitSampleInfo>();
|
private readonly BindableList<HitSampleInfo> samplesBindable = new BindableList<HitSampleInfo>();
|
||||||
private readonly Bindable<bool> userPositionalHitSounds = new Bindable<bool>();
|
|
||||||
|
|
||||||
private readonly Bindable<int> comboIndexBindable = new Bindable<int>();
|
private readonly Bindable<int> comboIndexBindable = new Bindable<int>();
|
||||||
|
|
||||||
|
private readonly Bindable<float> positionalHitsoundsLevel = new Bindable<float>();
|
||||||
private readonly Bindable<int> comboIndexWithOffsetsBindable = new Bindable<int>();
|
private readonly Bindable<int> comboIndexWithOffsetsBindable = new Bindable<int>();
|
||||||
|
|
||||||
protected override bool RequiresChildrenUpdate => true;
|
protected override bool RequiresChildrenUpdate => true;
|
||||||
@ -168,7 +168,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuConfigManager config, ISkinSource skinSource)
|
private void load(OsuConfigManager config, ISkinSource skinSource)
|
||||||
{
|
{
|
||||||
config.BindWith(OsuSetting.PositionalHitSounds, userPositionalHitSounds);
|
config.BindWith(OsuSetting.PositionalHitsoundsLevel, positionalHitsoundsLevel);
|
||||||
|
|
||||||
// Explicit non-virtual function call.
|
// Explicit non-virtual function call.
|
||||||
base.AddInternal(Samples = new PausableSkinnableSound());
|
base.AddInternal(Samples = new PausableSkinnableSound());
|
||||||
@ -532,9 +532,10 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
/// <param name="position">The lookup X position. Generally should be <see cref="SamplePlaybackPosition"/>.</param>
|
/// <param name="position">The lookup X position. Generally should be <see cref="SamplePlaybackPosition"/>.</param>
|
||||||
protected double CalculateSamplePlaybackBalance(double position)
|
protected double CalculateSamplePlaybackBalance(double position)
|
||||||
{
|
{
|
||||||
const float balance_adjust_amount = 0.4f;
|
float balanceAdjustAmount = positionalHitsoundsLevel.Value * 2;
|
||||||
|
double returnedvalue = balanceAdjustAmount * (position - 0.5f);
|
||||||
|
|
||||||
return balance_adjust_amount * (userPositionalHitSounds.Value ? position - 0.5f : 0);
|
return returnedvalue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -21,7 +21,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
|
|
||||||
public Func<float, bool> OnRotation;
|
public Func<float, bool> OnRotation;
|
||||||
public Func<Vector2, Anchor, bool> OnScale;
|
public Func<Vector2, Anchor, bool> OnScale;
|
||||||
public Func<Direction, bool> OnFlip;
|
public Func<Direction, bool, bool> OnFlip;
|
||||||
public Func<bool> OnReverse;
|
public Func<bool> OnReverse;
|
||||||
|
|
||||||
public Action OperationStarted;
|
public Action OperationStarted;
|
||||||
@ -174,12 +174,6 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
{
|
{
|
||||||
case Key.G:
|
case Key.G:
|
||||||
return CanReverse && runOperationFromHotkey(OnReverse);
|
return CanReverse && runOperationFromHotkey(OnReverse);
|
||||||
|
|
||||||
case Key.H:
|
|
||||||
return CanFlipX && runOperationFromHotkey(() => OnFlip?.Invoke(Direction.Horizontal) ?? false);
|
|
||||||
|
|
||||||
case Key.J:
|
|
||||||
return CanFlipY && runOperationFromHotkey(() => OnFlip?.Invoke(Direction.Vertical) ?? false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.OnKeyDown(e);
|
return base.OnKeyDown(e);
|
||||||
@ -287,12 +281,12 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
|
|
||||||
private void addXFlipComponents()
|
private void addXFlipComponents()
|
||||||
{
|
{
|
||||||
addButton(FontAwesome.Solid.ArrowsAltH, "Flip horizontally (Ctrl-H)", () => OnFlip?.Invoke(Direction.Horizontal));
|
addButton(FontAwesome.Solid.ArrowsAltH, "Flip horizontally", () => OnFlip?.Invoke(Direction.Horizontal, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addYFlipComponents()
|
private void addYFlipComponents()
|
||||||
{
|
{
|
||||||
addButton(FontAwesome.Solid.ArrowsAltV, "Flip vertically (Ctrl-J)", () => OnFlip?.Invoke(Direction.Vertical));
|
addButton(FontAwesome.Solid.ArrowsAltV, "Flip vertically", () => OnFlip?.Invoke(Direction.Vertical, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addButton(IconUsage icon, string tooltip, Action action)
|
private void addButton(IconUsage icon, string tooltip, Action action)
|
||||||
|
@ -17,6 +17,7 @@ using osu.Framework.Input.Events;
|
|||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Input.Bindings;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Input;
|
using osuTK.Input;
|
||||||
@ -26,7 +27,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A component which outlines items and handles movement of selections.
|
/// A component which outlines items and handles movement of selections.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class SelectionHandler<T> : CompositeDrawable, IKeyBindingHandler<PlatformAction>, IHasContextMenu
|
public abstract class SelectionHandler<T> : CompositeDrawable, IKeyBindingHandler<PlatformAction>, IKeyBindingHandler<GlobalAction>, IHasContextMenu
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The currently selected blueprints.
|
/// The currently selected blueprints.
|
||||||
@ -127,9 +128,10 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles the selected items being flipped.
|
/// Handles the selected items being flipped.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="direction">The direction to flip</param>
|
/// <param name="direction">The direction to flip.</param>
|
||||||
|
/// <param name="flipOverOrigin">Whether the flip operation should be global to the playfield's origin or local to the selected pattern.</param>
|
||||||
/// <returns>Whether any items could be flipped.</returns>
|
/// <returns>Whether any items could be flipped.</returns>
|
||||||
public virtual bool HandleFlip(Direction direction) => false;
|
public virtual bool HandleFlip(Direction direction, bool flipOverOrigin) => false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles the selected items being reversed pattern-wise.
|
/// Handles the selected items being reversed pattern-wise.
|
||||||
@ -137,6 +139,27 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
/// <returns>Whether any items could be reversed.</returns>
|
/// <returns>Whether any items could be reversed.</returns>
|
||||||
public virtual bool HandleReverse() => false;
|
public virtual bool HandleReverse() => false;
|
||||||
|
|
||||||
|
public virtual bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
|
||||||
|
{
|
||||||
|
if (e.Repeat)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch (e.Action)
|
||||||
|
{
|
||||||
|
case GlobalAction.EditorFlipHorizontally:
|
||||||
|
return HandleFlip(Direction.Horizontal, true);
|
||||||
|
|
||||||
|
case GlobalAction.EditorFlipVertically:
|
||||||
|
return HandleFlip(Direction.Vertical, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnReleased(KeyBindingReleaseEvent<GlobalAction> e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public bool OnPressed(KeyBindingPressEvent<PlatformAction> e)
|
public bool OnPressed(KeyBindingPressEvent<PlatformAction> e)
|
||||||
{
|
{
|
||||||
switch (e.Action)
|
switch (e.Action)
|
||||||
|
@ -7,7 +7,6 @@ using System.Diagnostics;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Input.Bindings;
|
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Input.Bindings;
|
using osu.Game.Input.Bindings;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
@ -17,7 +16,7 @@ using osuTK.Input;
|
|||||||
|
|
||||||
namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||||
{
|
{
|
||||||
internal class TimelineSelectionHandler : EditorSelectionHandler, IKeyBindingHandler<GlobalAction>
|
internal class TimelineSelectionHandler : EditorSelectionHandler
|
||||||
{
|
{
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private Timeline timeline { get; set; }
|
private Timeline timeline { get; set; }
|
||||||
@ -27,7 +26,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
// for now we always allow movement. snapping is provided by the Timeline's "distance" snap implementation
|
// for now we always allow movement. snapping is provided by the Timeline's "distance" snap implementation
|
||||||
public override bool HandleMovement(MoveSelectionEvent<HitObject> moveEvent) => true;
|
public override bool HandleMovement(MoveSelectionEvent<HitObject> moveEvent) => true;
|
||||||
|
|
||||||
public bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
|
public override bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
|
||||||
{
|
{
|
||||||
switch (e.Action)
|
switch (e.Action)
|
||||||
{
|
{
|
||||||
@ -40,11 +39,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return base.OnPressed(e);
|
||||||
}
|
|
||||||
|
|
||||||
public void OnReleased(KeyBindingReleaseEvent<GlobalAction> e)
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System.Diagnostics;
|
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -67,18 +66,34 @@ namespace osu.Game.Skinning.Editor
|
|||||||
|
|
||||||
public override void Show()
|
public override void Show()
|
||||||
{
|
{
|
||||||
// base call intentionally omitted.
|
// base call intentionally omitted as we have custom behaviour.
|
||||||
if (skinEditor == null)
|
|
||||||
|
if (skinEditor != null)
|
||||||
{
|
{
|
||||||
skinEditor = new SkinEditor(target);
|
|
||||||
skinEditor.State.BindValueChanged(editorVisibilityChanged);
|
|
||||||
|
|
||||||
Debug.Assert(skinEditor != null);
|
|
||||||
|
|
||||||
LoadComponentAsync(skinEditor, AddInternal);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
skinEditor.Show();
|
skinEditor.Show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var editor = new SkinEditor(target);
|
||||||
|
editor.State.BindValueChanged(editorVisibilityChanged);
|
||||||
|
|
||||||
|
skinEditor = editor;
|
||||||
|
|
||||||
|
// Schedule ensures that if `Show` is called before this overlay is loaded,
|
||||||
|
// it will not throw (LoadComponentAsync requires the load target to be in a loaded state).
|
||||||
|
Schedule(() =>
|
||||||
|
{
|
||||||
|
if (editor != skinEditor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
LoadComponentAsync(editor, _ =>
|
||||||
|
{
|
||||||
|
if (editor != skinEditor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
AddInternal(editor);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void editorVisibilityChanged(ValueChangedEvent<Visibility> visibility)
|
private void editorVisibilityChanged(ValueChangedEvent<Visibility> visibility)
|
||||||
|
@ -126,7 +126,7 @@ namespace osu.Game.Skinning.Editor
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool HandleFlip(Direction direction)
|
public override bool HandleFlip(Direction direction, bool flipOverOrigin)
|
||||||
{
|
{
|
||||||
var selectionQuad = getSelectionQuad();
|
var selectionQuad = getSelectionQuad();
|
||||||
Vector2 scaleFactor = direction == Direction.Horizontal ? new Vector2(-1, 1) : new Vector2(1, -1);
|
Vector2 scaleFactor = direction == Direction.Horizontal ? new Vector2(-1, 1) : new Vector2(1, -1);
|
||||||
@ -135,7 +135,7 @@ namespace osu.Game.Skinning.Editor
|
|||||||
{
|
{
|
||||||
var drawableItem = (Drawable)b.Item;
|
var drawableItem = (Drawable)b.Item;
|
||||||
|
|
||||||
var flippedPosition = GetFlippedPosition(direction, selectionQuad, b.ScreenSpaceSelectionPoint);
|
var flippedPosition = GetFlippedPosition(direction, flipOverOrigin ? drawableItem.Parent.ScreenSpaceDrawQuad : selectionQuad, b.ScreenSpaceSelectionPoint);
|
||||||
|
|
||||||
updateDrawablePosition(drawableItem, flippedPosition);
|
updateDrawablePosition(drawableItem, flippedPosition);
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=AssignedValueIsNeverUsed/@EntryIndexedValue">HINT</s:String>
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=AssignedValueIsNeverUsed/@EntryIndexedValue">HINT</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=AssignmentIsFullyDiscarded/@EntryIndexedValue">DO_NOT_SHOW</s:String>
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=AssignmentIsFullyDiscarded/@EntryIndexedValue">DO_NOT_SHOW</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=AssignNullToNotNullAttribute/@EntryIndexedValue">WARNING</s:String>
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=AssignNullToNotNullAttribute/@EntryIndexedValue">WARNING</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=AsyncVoidMethod/@EntryIndexedValue">WARNING</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=AutoPropertyCanBeMadeGetOnly_002EGlobal/@EntryIndexedValue">HINT</s:String>
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=AutoPropertyCanBeMadeGetOnly_002EGlobal/@EntryIndexedValue">HINT</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=AutoPropertyCanBeMadeGetOnly_002ELocal/@EntryIndexedValue">HINT</s:String>
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=AutoPropertyCanBeMadeGetOnly_002ELocal/@EntryIndexedValue">HINT</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=BadAttributeBracketsSpaces/@EntryIndexedValue">WARNING</s:String>
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=BadAttributeBracketsSpaces/@EntryIndexedValue">WARNING</s:String>
|
||||||
@ -231,6 +232,7 @@
|
|||||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UnusedType_002EGlobal/@EntryIndexedValue">HINT</s:String>
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UnusedType_002EGlobal/@EntryIndexedValue">HINT</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UseAwaitUsing/@EntryIndexedValue">DO_NOT_SHOW</s:String>
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UseAwaitUsing/@EntryIndexedValue">DO_NOT_SHOW</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UseCollectionCountProperty/@EntryIndexedValue">WARNING</s:String>
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UseCollectionCountProperty/@EntryIndexedValue">WARNING</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UseConfigureAwaitFalseForAsyncDisposable/@EntryIndexedValue">WARNING</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UseFormatSpecifierInFormatString/@EntryIndexedValue">WARNING</s:String>
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UseFormatSpecifierInFormatString/@EntryIndexedValue">WARNING</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UseFormatSpecifierInInterpolation/@EntryIndexedValue">WARNING</s:String>
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UseFormatSpecifierInInterpolation/@EntryIndexedValue">WARNING</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UseIndexFromEndExpression/@EntryIndexedValue">WARNING</s:String>
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UseIndexFromEndExpression/@EntryIndexedValue">WARNING</s:String>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user