mirror of
https://github.com/osukey/osukey.git
synced 2025-08-05 07:33:55 +09:00
Merge branch 'master' into maintain-common-mod-selection
This commit is contained in:
@ -25,6 +25,26 @@ namespace osu.Game.Screens.Edit
|
||||
BindValueChanged(_ => ensureValidDivisor());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set a divisor, updating the valid divisor range appropriately.
|
||||
/// </summary>
|
||||
/// <param name="divisor">The intended divisor.</param>
|
||||
public void SetArbitraryDivisor(int divisor)
|
||||
{
|
||||
// If the current valid divisor range doesn't contain the proposed value, attempt to find one which does.
|
||||
if (!ValidDivisors.Value.Presets.Contains(divisor))
|
||||
{
|
||||
if (BeatDivisorPresetCollection.COMMON.Presets.Contains(divisor))
|
||||
ValidDivisors.Value = BeatDivisorPresetCollection.COMMON;
|
||||
else if (BeatDivisorPresetCollection.TRIPLETS.Presets.Contains(divisor))
|
||||
ValidDivisors.Value = BeatDivisorPresetCollection.TRIPLETS;
|
||||
else
|
||||
ValidDivisors.Value = BeatDivisorPresetCollection.Custom(divisor);
|
||||
}
|
||||
|
||||
Value = divisor;
|
||||
}
|
||||
|
||||
private void updateBindableProperties()
|
||||
{
|
||||
ensureValidDivisor();
|
||||
|
@ -1,28 +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.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Screens.Edit.Components
|
||||
{
|
||||
public class CircularButton : OsuButton
|
||||
{
|
||||
private const float width = 125;
|
||||
private const float height = 30;
|
||||
|
||||
public CircularButton()
|
||||
{
|
||||
Size = new Vector2(width, height);
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
Content.CornerRadius = DrawHeight / 2f;
|
||||
Content.CornerExponent = 2;
|
||||
}
|
||||
}
|
||||
}
|
@ -8,13 +8,12 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Graphics.Effects;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Overlays;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@ -30,9 +29,9 @@ namespace osu.Game.Screens.Edit.Components.RadioButtons
|
||||
public readonly RadioButton Button;
|
||||
|
||||
private Color4 defaultBackgroundColour;
|
||||
private Color4 defaultBubbleColour;
|
||||
private Color4 defaultIconColour;
|
||||
private Color4 selectedBackgroundColour;
|
||||
private Color4 selectedBubbleColour;
|
||||
private Color4 selectedIconColour;
|
||||
|
||||
private Drawable icon;
|
||||
|
||||
@ -50,20 +49,13 @@ namespace osu.Game.Screens.Edit.Components.RadioButtons
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
defaultBackgroundColour = colours.Gray3;
|
||||
defaultBubbleColour = defaultBackgroundColour.Darken(0.5f);
|
||||
selectedBackgroundColour = colours.BlueDark;
|
||||
selectedBubbleColour = selectedBackgroundColour.Lighten(0.5f);
|
||||
defaultBackgroundColour = colourProvider.Background3;
|
||||
selectedBackgroundColour = colourProvider.Background1;
|
||||
|
||||
Content.EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Radius = 2,
|
||||
Offset = new Vector2(0, 1),
|
||||
Colour = Color4.Black.Opacity(0.5f)
|
||||
};
|
||||
defaultIconColour = defaultBackgroundColour.Darken(0.5f);
|
||||
selectedIconColour = selectedBackgroundColour.Lighten(0.5f);
|
||||
|
||||
Add(icon = (Button.CreateIcon?.Invoke() ?? new Circle()).With(b =>
|
||||
{
|
||||
@ -98,7 +90,7 @@ namespace osu.Game.Screens.Edit.Components.RadioButtons
|
||||
return;
|
||||
|
||||
BackgroundColour = Button.Selected.Value ? selectedBackgroundColour : defaultBackgroundColour;
|
||||
icon.Colour = Button.Selected.Value ? selectedBubbleColour : defaultBubbleColour;
|
||||
icon.Colour = Button.Selected.Value ? selectedIconColour : defaultIconColour;
|
||||
}
|
||||
|
||||
protected override SpriteText CreateText() => new OsuSpriteText
|
||||
|
@ -6,12 +6,11 @@
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Effects;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Overlays;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@ -20,9 +19,9 @@ namespace osu.Game.Screens.Edit.Components.TernaryButtons
|
||||
internal class DrawableTernaryButton : OsuButton
|
||||
{
|
||||
private Color4 defaultBackgroundColour;
|
||||
private Color4 defaultBubbleColour;
|
||||
private Color4 defaultIconColour;
|
||||
private Color4 selectedBackgroundColour;
|
||||
private Color4 selectedBubbleColour;
|
||||
private Color4 selectedIconColour;
|
||||
|
||||
private Drawable icon;
|
||||
|
||||
@ -38,20 +37,13 @@ namespace osu.Game.Screens.Edit.Components.TernaryButtons
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
defaultBackgroundColour = colours.Gray3;
|
||||
defaultBubbleColour = defaultBackgroundColour.Darken(0.5f);
|
||||
selectedBackgroundColour = colours.BlueDark;
|
||||
selectedBubbleColour = selectedBackgroundColour.Lighten(0.5f);
|
||||
defaultBackgroundColour = colourProvider.Background3;
|
||||
selectedBackgroundColour = colourProvider.Background1;
|
||||
|
||||
Content.EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Radius = 2,
|
||||
Offset = new Vector2(0, 1),
|
||||
Colour = Color4.Black.Opacity(0.5f)
|
||||
};
|
||||
defaultIconColour = defaultBackgroundColour.Darken(0.5f);
|
||||
selectedIconColour = selectedBackgroundColour.Lighten(0.5f);
|
||||
|
||||
Add(icon = (Button.CreateIcon?.Invoke() ?? new Circle()).With(b =>
|
||||
{
|
||||
@ -85,17 +77,17 @@ namespace osu.Game.Screens.Edit.Components.TernaryButtons
|
||||
switch (Button.Bindable.Value)
|
||||
{
|
||||
case TernaryState.Indeterminate:
|
||||
icon.Colour = selectedBubbleColour.Darken(0.5f);
|
||||
icon.Colour = selectedIconColour.Darken(0.5f);
|
||||
BackgroundColour = selectedBackgroundColour.Darken(0.5f);
|
||||
break;
|
||||
|
||||
case TernaryState.False:
|
||||
icon.Colour = defaultBubbleColour;
|
||||
icon.Colour = defaultIconColour;
|
||||
BackgroundColour = defaultBackgroundColour;
|
||||
break;
|
||||
|
||||
case TernaryState.True:
|
||||
icon.Colour = selectedBubbleColour;
|
||||
icon.Colour = selectedIconColour;
|
||||
BackgroundColour = selectedBackgroundColour;
|
||||
break;
|
||||
}
|
||||
|
@ -57,15 +57,13 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
|
||||
|
||||
private void updateRelativeChildSize()
|
||||
{
|
||||
// the track may not be loaded completely (only has a length once it is).
|
||||
if (!beatmap.Value.Track.IsLoaded)
|
||||
{
|
||||
content.RelativeChildSize = Vector2.One;
|
||||
Schedule(updateRelativeChildSize);
|
||||
return;
|
||||
}
|
||||
// If the track is not loaded, assign a default sane length otherwise relative positioning becomes meaningless.
|
||||
double trackLength = beatmap.Value.Track.IsLoaded ? beatmap.Value.Track.Length : 60000;
|
||||
content.RelativeChildSize = new Vector2((float)Math.Max(1, trackLength), 1);
|
||||
|
||||
content.RelativeChildSize = new Vector2((float)Math.Max(1, beatmap.Value.Track.Length), 1);
|
||||
// The track may not be loaded completely (only has a length once it is).
|
||||
if (!beatmap.Value.Track.IsLoaded)
|
||||
Schedule(updateRelativeChildSize);
|
||||
}
|
||||
|
||||
protected virtual void LoadBeatmap(EditorBeatmap beatmap)
|
||||
|
@ -209,6 +209,17 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool OnKeyDown(KeyDownEvent e)
|
||||
{
|
||||
if (e.ShiftPressed && e.Key >= Key.Number1 && e.Key <= Key.Number9)
|
||||
{
|
||||
beatDivisor.SetArbitraryDivisor(e.Key - Key.Number0);
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.OnKeyDown(e);
|
||||
}
|
||||
|
||||
internal class DivisorDisplay : OsuAnimatedButton, IHasPopover
|
||||
{
|
||||
public BindableBeatDivisor BeatDivisor { get; } = new BindableBeatDivisor();
|
||||
@ -306,17 +317,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
return;
|
||||
}
|
||||
|
||||
if (!BeatDivisor.ValidDivisors.Value.Presets.Contains(divisor))
|
||||
{
|
||||
if (BeatDivisorPresetCollection.COMMON.Presets.Contains(divisor))
|
||||
BeatDivisor.ValidDivisors.Value = BeatDivisorPresetCollection.COMMON;
|
||||
else if (BeatDivisorPresetCollection.TRIPLETS.Presets.Contains(divisor))
|
||||
BeatDivisor.ValidDivisors.Value = BeatDivisorPresetCollection.TRIPLETS;
|
||||
else
|
||||
BeatDivisor.ValidDivisors.Value = BeatDivisorPresetCollection.Custom(divisor);
|
||||
}
|
||||
|
||||
BeatDivisor.Value = divisor;
|
||||
BeatDivisor.SetArbitraryDivisor(divisor);
|
||||
|
||||
this.HidePopover();
|
||||
}
|
||||
|
@ -53,9 +53,16 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
float maxDistance = new Vector2(dx, dy).Length;
|
||||
int requiredCircles = Math.Min(MaxIntervals, (int)(maxDistance / DistanceBetweenTicks));
|
||||
|
||||
// We need to offset the drawn lines to the next valid snap for the currently selected divisor.
|
||||
//
|
||||
// Picture the scenario where the user has just placed an object on a 1/2 snap, then changes to
|
||||
// 1/3 snap and expects to be able to place the next object on a valid 1/3 snap, regardless of the
|
||||
// fact that the 1/2 snap reference object is not valid for 1/3 snapping.
|
||||
float offset = SnapProvider.FindSnappedDistance(ReferenceObject, 0);
|
||||
|
||||
for (int i = 0; i < requiredCircles; i++)
|
||||
{
|
||||
float diameter = (i + 1) * DistanceBetweenTicks * 2;
|
||||
float diameter = (offset + (i + 1) * DistanceBetweenTicks) * 2;
|
||||
|
||||
AddInternal(new Ring(ReferenceObject, GetColourForIndexFromPlacement(i))
|
||||
{
|
||||
|
@ -97,7 +97,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
private void updateSpacing()
|
||||
{
|
||||
float distanceSpacingMultiplier = (float)DistanceSpacingMultiplier.Value;
|
||||
float beatSnapDistance = SnapProvider.GetBeatSnapDistanceAt(ReferenceObject);
|
||||
float beatSnapDistance = SnapProvider.GetBeatSnapDistanceAt(ReferenceObject, false);
|
||||
|
||||
DistanceBetweenTicks = beatSnapDistance * distanceSpacingMultiplier;
|
||||
|
||||
|
@ -250,7 +250,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
|
||||
private void seekTrackToCurrent()
|
||||
{
|
||||
double target = Current / Content.DrawWidth * editorClock.TrackLength;
|
||||
double target = TimeAtPosition(Current);
|
||||
editorClock.Seek(Math.Min(editorClock.TrackLength, target));
|
||||
}
|
||||
|
||||
@ -264,7 +264,8 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
if (handlingDragInput)
|
||||
editorClock.Stop();
|
||||
|
||||
ScrollTo((float)(editorClock.CurrentTime / editorClock.TrackLength) * Content.DrawWidth, false);
|
||||
float position = PositionAtTime(editorClock.CurrentTime);
|
||||
ScrollTo(position, false);
|
||||
}
|
||||
|
||||
protected override bool OnMouseDown(MouseDownEvent e)
|
||||
|
@ -304,6 +304,7 @@ namespace osu.Game.Screens.Edit
|
||||
cutMenuItem = new EditorMenuItem("Cut", MenuItemType.Standard, Cut),
|
||||
copyMenuItem = new EditorMenuItem("Copy", MenuItemType.Standard, Copy),
|
||||
pasteMenuItem = new EditorMenuItem("Paste", MenuItemType.Standard, Paste),
|
||||
cloneMenuItem = new EditorMenuItem("Clone", MenuItemType.Standard, Clone),
|
||||
}
|
||||
},
|
||||
new MenuItem("View")
|
||||
@ -575,6 +576,10 @@ namespace osu.Game.Screens.Edit
|
||||
this.Exit();
|
||||
return true;
|
||||
|
||||
case GlobalAction.EditorCloneSelection:
|
||||
Clone();
|
||||
return true;
|
||||
|
||||
case GlobalAction.EditorComposeMode:
|
||||
Mode.Value = EditorScreenMode.Compose;
|
||||
return true;
|
||||
@ -741,6 +746,7 @@ namespace osu.Game.Screens.Edit
|
||||
|
||||
private EditorMenuItem cutMenuItem;
|
||||
private EditorMenuItem copyMenuItem;
|
||||
private EditorMenuItem cloneMenuItem;
|
||||
private EditorMenuItem pasteMenuItem;
|
||||
|
||||
private readonly BindableWithCurrent<bool> canCut = new BindableWithCurrent<bool>();
|
||||
@ -750,7 +756,11 @@ namespace osu.Game.Screens.Edit
|
||||
private void setUpClipboardActionAvailability()
|
||||
{
|
||||
canCut.Current.BindValueChanged(cut => cutMenuItem.Action.Disabled = !cut.NewValue, true);
|
||||
canCopy.Current.BindValueChanged(copy => copyMenuItem.Action.Disabled = !copy.NewValue, true);
|
||||
canCopy.Current.BindValueChanged(copy =>
|
||||
{
|
||||
copyMenuItem.Action.Disabled = !copy.NewValue;
|
||||
cloneMenuItem.Action.Disabled = !copy.NewValue;
|
||||
}, true);
|
||||
canPaste.Current.BindValueChanged(paste => pasteMenuItem.Action.Disabled = !paste.NewValue, true);
|
||||
}
|
||||
|
||||
@ -765,6 +775,21 @@ namespace osu.Game.Screens.Edit
|
||||
|
||||
protected void Copy() => currentScreen?.Copy();
|
||||
|
||||
protected void Clone()
|
||||
{
|
||||
// Avoid attempting to clone if copying is not available (as it may result in pasting something unexpected).
|
||||
if (!canCopy.Value)
|
||||
return;
|
||||
|
||||
// This is an initial implementation just to get an idea of how people used this function.
|
||||
// There are a couple of differences from osu!stable's implementation which will require more work to match:
|
||||
// - The "clipboard" is not populated during the duplication process.
|
||||
// - The duplicated hitobjects are inserted after the original pattern (add one beat_length and then quantize using beat snap).
|
||||
// - The duplicated hitobjects are selected (but this is also applied for all paste operations so should be changed there).
|
||||
Copy();
|
||||
Paste();
|
||||
}
|
||||
|
||||
protected void Paste() => currentScreen?.Paste();
|
||||
|
||||
#endregion
|
||||
|
@ -27,7 +27,7 @@ namespace osu.Game.Screens.Edit
|
||||
|
||||
private readonly Bindable<Track> track = new Bindable<Track>();
|
||||
|
||||
public double TrackLength => track.Value?.Length ?? 60000;
|
||||
public double TrackLength => track.Value?.IsLoaded == true ? track.Value.Length : 60000;
|
||||
|
||||
public ControlPointInfo ControlPointInfo => Beatmap.ControlPointInfo;
|
||||
|
||||
|
@ -106,7 +106,6 @@ namespace osu.Game.Screens.Edit
|
||||
Name = "Main content",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Depth = float.MaxValue,
|
||||
Padding = new MarginPadding(10),
|
||||
Child = spinner = new LoadingSpinner(true)
|
||||
{
|
||||
State = { Value = Visibility.Visible },
|
||||
|
@ -41,6 +41,11 @@ namespace osu.Game.Screens
|
||||
/// </summary>
|
||||
bool HideOverlaysOnEnter { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the menu cursor should be hidden when non-mouse input is received.
|
||||
/// </summary>
|
||||
bool HideMenuCursorOnNonMouseInput { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether overlays should be able to be opened when this screen is current.
|
||||
/// </summary>
|
||||
|
@ -113,7 +113,7 @@ namespace osu.Game.Screens.Menu
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
logoBounceContainer = new DragContainer
|
||||
logoBounceContainer = new Container
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
@ -407,27 +407,24 @@ namespace osu.Game.Screens.Menu
|
||||
impactContainer.ScaleTo(1.12f, 250);
|
||||
}
|
||||
|
||||
private class DragContainer : Container
|
||||
public override bool DragBlocksClick => false;
|
||||
|
||||
protected override bool OnDragStart(DragStartEvent e) => true;
|
||||
|
||||
protected override void OnDrag(DragEvent e)
|
||||
{
|
||||
public override bool DragBlocksClick => false;
|
||||
Vector2 change = e.MousePosition - e.MouseDownPosition;
|
||||
|
||||
protected override bool OnDragStart(DragStartEvent e) => true;
|
||||
// Diminish the drag distance as we go further to simulate "rubber band" feeling.
|
||||
change *= change.Length <= 0 ? 0 : MathF.Pow(change.Length, 0.6f) / change.Length;
|
||||
|
||||
protected override void OnDrag(DragEvent e)
|
||||
{
|
||||
Vector2 change = e.MousePosition - e.MouseDownPosition;
|
||||
logoBounceContainer.MoveTo(change);
|
||||
}
|
||||
|
||||
// Diminish the drag distance as we go further to simulate "rubber band" feeling.
|
||||
change *= change.Length <= 0 ? 0 : MathF.Pow(change.Length, 0.6f) / change.Length;
|
||||
|
||||
this.MoveTo(change);
|
||||
}
|
||||
|
||||
protected override void OnDragEnd(DragEndEvent e)
|
||||
{
|
||||
this.MoveTo(Vector2.Zero, 800, Easing.OutElastic);
|
||||
base.OnDragEnd(e);
|
||||
}
|
||||
protected override void OnDragEnd(DragEndEvent e)
|
||||
{
|
||||
logoBounceContainer.MoveTo(Vector2.Zero, 800, Easing.OutElastic);
|
||||
base.OnDragEnd(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -78,9 +78,13 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist
|
||||
return;
|
||||
|
||||
bool isItemOwner = Item.OwnerID == api.LocalUser.Value.OnlineID || multiplayerClient.IsHost;
|
||||
bool isValidItem = isItemOwner && !Item.Expired;
|
||||
|
||||
AllowDeletion = isItemOwner && !Item.Expired && Item.ID != multiplayerClient.Room.Settings.PlaylistItemId;
|
||||
AllowEditing = isItemOwner && !Item.Expired;
|
||||
AllowDeletion = isValidItem
|
||||
&& (Item.ID != multiplayerClient.Room.Settings.PlaylistItemId // This is an optimisation for the following check.
|
||||
|| multiplayerClient.Room.Playlist.Count(i => !i.Expired) > 1);
|
||||
|
||||
AllowEditing = isValidItem;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
|
@ -182,7 +182,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
|
||||
/// <param name="pivot">An optional pivot around which the scores were retrieved.</param>
|
||||
private void performSuccessCallback([NotNull] Action<IEnumerable<ScoreInfo>> callback, [NotNull] List<MultiplayerScore> scores, [CanBeNull] MultiplayerScores pivot = null) => Schedule(() =>
|
||||
{
|
||||
var scoreInfos = scoreManager.OrderByTotalScore(scores.Select(s => s.CreateScoreInfo(rulesets, playlistItem, Beatmap.Value.BeatmapInfo))).ToArray();
|
||||
var scoreInfos = scoreManager.OrderByTotalScore(scores.Select(s => s.CreateScoreInfo(scoreManager, rulesets, playlistItem, Beatmap.Value.BeatmapInfo))).ToArray();
|
||||
|
||||
// Select a score if we don't already have one selected.
|
||||
// Note: This is done before the callback so that the panel list centres on the selected score before panels are added (eliminating initial scroll).
|
||||
|
@ -40,11 +40,10 @@ namespace osu.Game.Screens
|
||||
|
||||
public virtual bool AllowExternalScreenChange => false;
|
||||
|
||||
/// <summary>
|
||||
/// Whether all overlays should be hidden when this screen is entered or resumed.
|
||||
/// </summary>
|
||||
public virtual bool HideOverlaysOnEnter => false;
|
||||
|
||||
public virtual bool HideMenuCursorOnNonMouseInput => false;
|
||||
|
||||
/// <summary>
|
||||
/// The initial overlay activation mode to use when this screen is entered for the first time.
|
||||
/// </summary>
|
||||
|
@ -9,7 +9,6 @@ using osu.Game.Configuration;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Screens.Play.HUD
|
||||
@ -45,12 +44,6 @@ namespace osu.Game.Screens.Play.HUD
|
||||
[Resolved]
|
||||
private DrawableRuleset? drawableRuleset { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private OsuConfigManager config { get; set; } = null!;
|
||||
|
||||
[Resolved]
|
||||
private SkinManager skinManager { get; set; } = null!;
|
||||
|
||||
public DefaultSongProgress()
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
@ -100,47 +93,6 @@ namespace osu.Game.Screens.Play.HUD
|
||||
{
|
||||
AllowSeeking.BindValueChanged(_ => updateBarVisibility(), true);
|
||||
ShowGraph.BindValueChanged(_ => updateGraphVisibility(), true);
|
||||
|
||||
migrateSettingFromConfig();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This setting has been migrated to a per-component level.
|
||||
/// Only take the value from the config if it is in a non-default state (then reset it to default so it only applies once).
|
||||
///
|
||||
/// Can be removed 20221027.
|
||||
/// </summary>
|
||||
private void migrateSettingFromConfig()
|
||||
{
|
||||
Bindable<bool> configShowGraph = config.GetBindable<bool>(OsuSetting.ShowProgressGraph);
|
||||
|
||||
if (!configShowGraph.IsDefault)
|
||||
{
|
||||
ShowGraph.Value = configShowGraph.Value;
|
||||
|
||||
// This is pretty ugly, but the only way to make this stick...
|
||||
var skinnableTarget = this.FindClosestParent<ISkinnableTarget>();
|
||||
|
||||
if (skinnableTarget != null)
|
||||
{
|
||||
// If the skin is not mutable, a mutable instance will be created, causing this migration logic to run again on the correct skin.
|
||||
// Therefore we want to avoid resetting the config value on this invocation.
|
||||
if (skinManager.EnsureMutableSkin())
|
||||
return;
|
||||
|
||||
// If `EnsureMutableSkin` actually changed the skin, default layout may take a frame to apply.
|
||||
// See `SkinnableTargetComponentsContainer`'s use of ScheduleAfterChildren.
|
||||
ScheduleAfterChildren(() =>
|
||||
{
|
||||
var skin = skinManager.CurrentSkin.Value;
|
||||
skin.UpdateDrawableTarget(skinnableTarget);
|
||||
|
||||
skinManager.Save(skin);
|
||||
});
|
||||
|
||||
configShowGraph.SetDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void PopIn()
|
||||
|
@ -15,6 +15,7 @@ using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
@ -44,8 +45,8 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
|
||||
public Bindable<LabelStyles> LabelStyle { get; } = new Bindable<LabelStyles>(LabelStyles.Icons);
|
||||
|
||||
private SpriteIcon arrow;
|
||||
private Drawable labelEarly;
|
||||
private Drawable labelLate;
|
||||
private UprightAspectMaintainingContainer labelEarly;
|
||||
private UprightAspectMaintainingContainer labelLate;
|
||||
|
||||
private Container colourBarsEarly;
|
||||
private Container colourBarsLate;
|
||||
@ -122,6 +123,20 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Width = judgement_line_width,
|
||||
},
|
||||
labelEarly = new UprightAspectMaintainingContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.Centre,
|
||||
Y = -10,
|
||||
},
|
||||
labelLate = new UprightAspectMaintainingContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.Centre,
|
||||
Y = 10,
|
||||
},
|
||||
}
|
||||
},
|
||||
arrowContainer = new Container
|
||||
@ -261,57 +276,41 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
|
||||
{
|
||||
const float icon_size = 14;
|
||||
|
||||
labelEarly?.Expire();
|
||||
labelEarly = null;
|
||||
|
||||
labelLate?.Expire();
|
||||
labelLate = null;
|
||||
|
||||
switch (style)
|
||||
{
|
||||
case LabelStyles.None:
|
||||
labelEarly.Clear();
|
||||
labelLate.Clear();
|
||||
break;
|
||||
|
||||
case LabelStyles.Icons:
|
||||
labelEarly = new SpriteIcon
|
||||
labelEarly.Child = new SpriteIcon
|
||||
{
|
||||
Y = -10,
|
||||
Size = new Vector2(icon_size),
|
||||
Icon = FontAwesome.Solid.ShippingFast,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.Centre,
|
||||
};
|
||||
|
||||
labelLate = new SpriteIcon
|
||||
labelLate.Child = new SpriteIcon
|
||||
{
|
||||
Y = 10,
|
||||
Size = new Vector2(icon_size),
|
||||
Icon = FontAwesome.Solid.Bicycle,
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.Centre,
|
||||
};
|
||||
|
||||
break;
|
||||
|
||||
case LabelStyles.Text:
|
||||
labelEarly = new OsuSpriteText
|
||||
labelEarly.Child = new OsuSpriteText
|
||||
{
|
||||
Y = -10,
|
||||
Text = "Early",
|
||||
Font = OsuFont.Default.With(size: 10),
|
||||
Height = 12,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.Centre,
|
||||
};
|
||||
|
||||
labelLate = new OsuSpriteText
|
||||
labelLate.Child = new OsuSpriteText
|
||||
{
|
||||
Y = 10,
|
||||
Text = "Late",
|
||||
Font = OsuFont.Default.With(size: 10),
|
||||
Height = 12,
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.Centre,
|
||||
};
|
||||
|
||||
break;
|
||||
@ -320,26 +319,8 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
|
||||
throw new ArgumentOutOfRangeException(nameof(style), style, null);
|
||||
}
|
||||
|
||||
if (labelEarly != null)
|
||||
{
|
||||
colourBars.Add(labelEarly);
|
||||
labelEarly.FadeInFromZero(500);
|
||||
}
|
||||
|
||||
if (labelLate != null)
|
||||
{
|
||||
colourBars.Add(labelLate);
|
||||
labelLate.FadeInFromZero(500);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
// undo any layout rotation to display icons in the correct orientation
|
||||
if (labelEarly != null) labelEarly.Rotation = -Rotation;
|
||||
if (labelLate != null) labelLate.Rotation = -Rotation;
|
||||
labelEarly.FadeInFromZero(500);
|
||||
labelLate.FadeInFromZero(500);
|
||||
}
|
||||
|
||||
private void createColourBars((HitResult result, double length)[] windows)
|
||||
|
@ -39,9 +39,16 @@ namespace osu.Game.Screens.Play
|
||||
/// </summary>
|
||||
public float BottomScoringElementsHeight { get; private set; }
|
||||
|
||||
// HUD uses AlwaysVisible on child components so they can be in an updated state for next display.
|
||||
// Without blocking input, this would also allow them to be interacted with in such a state.
|
||||
public override bool PropagatePositionalInputSubTree => ShowHud.Value;
|
||||
protected override bool ShouldBeConsideredForInput(Drawable child)
|
||||
{
|
||||
// HUD uses AlwaysVisible on child components so they can be in an updated state for next display.
|
||||
// Without blocking input, this would also allow them to be interacted with in such a state.
|
||||
if (ShowHud.Value)
|
||||
return base.ShouldBeConsideredForInput(child);
|
||||
|
||||
// hold to quit button should always be interactive.
|
||||
return child == bottomRightElements;
|
||||
}
|
||||
|
||||
public readonly KeyCounterDisplay KeyCounter;
|
||||
public readonly ModDisplay ModDisplay;
|
||||
|
@ -66,6 +66,8 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
public override bool HideOverlaysOnEnter => true;
|
||||
|
||||
public override bool HideMenuCursorOnNonMouseInput => true;
|
||||
|
||||
protected override OverlayActivation InitialOverlayActivationMode => OverlayActivation.UserTriggered;
|
||||
|
||||
// We are managing our own adjustments (see OnEntering/OnExiting).
|
||||
|
@ -64,6 +64,8 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
protected Task? DisposalTask { get; private set; }
|
||||
|
||||
private OsuScrollContainer settingsScroll = null!;
|
||||
|
||||
private bool backgroundBrightnessReduction;
|
||||
|
||||
private readonly BindableDouble volumeAdjustment = new BindableDouble(1);
|
||||
@ -71,6 +73,9 @@ namespace osu.Game.Screens.Play
|
||||
private AudioFilter lowPassFilter = null!;
|
||||
private AudioFilter highPassFilter = null!;
|
||||
|
||||
[Cached]
|
||||
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple);
|
||||
|
||||
protected bool BackgroundBrightnessReduction
|
||||
{
|
||||
set
|
||||
@ -165,30 +170,30 @@ namespace osu.Game.Screens.Play
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
},
|
||||
new OsuScrollContainer
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Width = SettingsToolboxGroup.CONTAINER_WIDTH + padding * 2,
|
||||
Padding = new MarginPadding { Vertical = padding },
|
||||
Masking = false,
|
||||
Child = PlayerSettings = new FillFlowContainer<PlayerSettingsGroup>
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(0, 20),
|
||||
Padding = new MarginPadding { Horizontal = padding },
|
||||
Children = new PlayerSettingsGroup[]
|
||||
{
|
||||
VisualSettings = new VisualSettings(),
|
||||
AudioSettings = new AudioSettings(),
|
||||
new InputSettings()
|
||||
}
|
||||
},
|
||||
},
|
||||
idleTracker = new IdleTracker(750),
|
||||
}),
|
||||
settingsScroll = new OsuScrollContainer
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Width = SettingsToolboxGroup.CONTAINER_WIDTH + padding * 2,
|
||||
Padding = new MarginPadding { Vertical = padding },
|
||||
Masking = false,
|
||||
Child = PlayerSettings = new FillFlowContainer<PlayerSettingsGroup>
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(0, 20),
|
||||
Padding = new MarginPadding { Horizontal = padding },
|
||||
Children = new PlayerSettingsGroup[]
|
||||
{
|
||||
VisualSettings = new VisualSettings(),
|
||||
AudioSettings = new AudioSettings(),
|
||||
new InputSettings()
|
||||
}
|
||||
},
|
||||
},
|
||||
idleTracker = new IdleTracker(750),
|
||||
lowPassFilter = new AudioFilter(audio.TrackMixer),
|
||||
highPassFilter = new AudioFilter(audio.TrackMixer, BQFType.HighPass)
|
||||
};
|
||||
@ -224,6 +229,9 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
Beatmap.Value.Track.AddAdjustment(AdjustableProperty.Volume, volumeAdjustment);
|
||||
|
||||
// Start off-screen.
|
||||
settingsScroll.MoveToX(settingsScroll.DrawWidth);
|
||||
|
||||
content.ScaleTo(0.7f);
|
||||
|
||||
contentIn();
|
||||
@ -313,6 +321,16 @@ namespace osu.Game.Screens.Play
|
||||
content.StopTracking();
|
||||
}
|
||||
|
||||
protected override void LogoSuspending(OsuLogo logo)
|
||||
{
|
||||
base.LogoSuspending(logo);
|
||||
content.StopTracking();
|
||||
|
||||
logo
|
||||
.FadeOut(CONTENT_OUT_DURATION / 2, Easing.OutQuint)
|
||||
.ScaleTo(logo.Scale * 0.8f, CONTENT_OUT_DURATION * 2, Easing.OutQuint);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
protected override void Update()
|
||||
@ -391,6 +409,10 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
content.FadeInFromZero(400);
|
||||
content.ScaleTo(1, 650, Easing.OutQuint).Then().Schedule(prepareNewPlayer);
|
||||
|
||||
settingsScroll.FadeInFromZero(500, Easing.Out)
|
||||
.MoveToX(0, 500, Easing.OutQuint);
|
||||
|
||||
lowPassFilter.CutoffTo(1000, 650, Easing.OutQuint);
|
||||
highPassFilter.CutoffTo(300).Then().CutoffTo(0, 1250); // 1250 is to line up with the appearance of MetadataInfo (750 delay + 500 fade-in)
|
||||
|
||||
@ -404,6 +426,10 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
content.ScaleTo(0.7f, CONTENT_OUT_DURATION * 2, Easing.OutQuint);
|
||||
content.FadeOut(CONTENT_OUT_DURATION, Easing.OutQuint);
|
||||
|
||||
settingsScroll.FadeOut(CONTENT_OUT_DURATION, Easing.OutQuint)
|
||||
.MoveToX(settingsScroll.DrawWidth, CONTENT_OUT_DURATION * 2, Easing.OutQuint);
|
||||
|
||||
lowPassFilter.CutoffTo(AudioFilter.MAX_LOWPASS_CUTOFF, CONTENT_OUT_DURATION);
|
||||
highPassFilter.CutoffTo(0, CONTENT_OUT_DURATION);
|
||||
}
|
||||
@ -432,7 +458,7 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
ContentOut();
|
||||
|
||||
TransformSequence<PlayerLoader> pushSequence = this.Delay(CONTENT_OUT_DURATION);
|
||||
TransformSequence<PlayerLoader> pushSequence = this.Delay(0);
|
||||
|
||||
// only show if the warning was created (i.e. the beatmap needs it)
|
||||
// and this is not a restart of the map (the warning expires after first load).
|
||||
@ -441,6 +467,7 @@ namespace osu.Game.Screens.Play
|
||||
const double epilepsy_display_length = 3000;
|
||||
|
||||
pushSequence
|
||||
.Delay(CONTENT_OUT_DURATION)
|
||||
.Schedule(() => epilepsyWarning.State.Value = Visibility.Visible)
|
||||
.TransformBindableTo(volumeAdjustment, 0.25, EpilepsyWarning.FADE_DURATION, Easing.OutQuint)
|
||||
.Delay(epilepsy_display_length)
|
||||
|
@ -1,22 +1,27 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Overlays.Settings;
|
||||
|
||||
namespace osu.Game.Screens.Play.PlayerSettings
|
||||
{
|
||||
public class PlayerCheckbox : OsuCheckbox
|
||||
public class PlayerCheckbox : SettingsCheckbox
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
protected override Drawable CreateControl() => new PlayerCheckboxControl();
|
||||
|
||||
public class PlayerCheckboxControl : OsuCheckbox
|
||||
{
|
||||
Nub.AccentColour = colours.Yellow;
|
||||
Nub.GlowingAccentColour = colours.YellowLighter;
|
||||
Nub.GlowColour = colours.YellowDark;
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
Nub.AccentColour = colours.Yellow;
|
||||
Nub.GlowingAccentColour = colours.YellowLighter;
|
||||
Nub.GlowColour = colours.YellowDark;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,9 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Localisation;
|
||||
|
||||
namespace osu.Game.Screens.Play.PlayerSettings
|
||||
@ -24,26 +21,16 @@ namespace osu.Game.Screens.Play.PlayerSettings
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = GameplaySettingsStrings.BackgroundDim
|
||||
},
|
||||
dimSliderBar = new PlayerSliderBar<double>
|
||||
{
|
||||
LabelText = GameplaySettingsStrings.BackgroundDim,
|
||||
DisplayAsPercentage = true
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = GameplaySettingsStrings.BackgroundBlur
|
||||
},
|
||||
blurSliderBar = new PlayerSliderBar<double>
|
||||
{
|
||||
LabelText = GameplaySettingsStrings.BackgroundBlur,
|
||||
DisplayAsPercentage = true
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = "Toggles:"
|
||||
},
|
||||
showStoryboardToggle = new PlayerCheckbox { LabelText = GraphicsSettingsStrings.StoryboardVideo },
|
||||
beatmapSkinsToggle = new PlayerCheckbox { LabelText = SkinSettingsStrings.BeatmapSkins },
|
||||
beatmapColorsToggle = new PlayerCheckbox { LabelText = SkinSettingsStrings.BeatmapColours },
|
||||
|
@ -86,16 +86,13 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
// Generally a timeout would not happen here as APIAccess will timeout first.
|
||||
if (!tcs.Task.Wait(60000))
|
||||
handleTokenFailure(new InvalidOperationException("Token retrieval timed out (request never run)"));
|
||||
req.TriggerFailure(new InvalidOperationException("Token retrieval timed out (request never run)"));
|
||||
|
||||
return true;
|
||||
|
||||
void handleTokenFailure(Exception exception)
|
||||
{
|
||||
// This method may be invoked multiple times due to the Task.Wait call above.
|
||||
// We only really care about the first error.
|
||||
if (!tcs.TrySetResult(false))
|
||||
return;
|
||||
tcs.SetResult(false);
|
||||
|
||||
if (HandleTokenRetrievalFailure(exception))
|
||||
{
|
||||
|
@ -36,12 +36,6 @@ namespace osu.Game.Screens.Ranking.Statistics
|
||||
/// </summary>
|
||||
public readonly bool RequiresHitEvents;
|
||||
|
||||
[Obsolete("Use constructor which takes creation function instead.")] // Can be removed 20220803.
|
||||
public StatisticItem([NotNull] string name, [NotNull] Drawable content, [CanBeNull] Dimension dimension = null)
|
||||
: this(name, () => content, true, dimension)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="StatisticItem"/>, to be displayed inside a <see cref="StatisticRow"/> in the results screen.
|
||||
/// </summary>
|
||||
|
@ -1048,7 +1048,7 @@ namespace osu.Game.Screens.Select
|
||||
|
||||
protected override void PerformSelection()
|
||||
{
|
||||
if (LastSelected == null || LastSelected.Filtered.Value)
|
||||
if (LastSelected == null)
|
||||
carousel?.SelectNextRandom();
|
||||
else
|
||||
base.PerformSelection();
|
||||
|
@ -108,10 +108,35 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
PerformSelection();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the item this group would select next if it attempted selection
|
||||
/// </summary>
|
||||
/// <returns>An unfiltered item nearest to the last selected one or null if all items are filtered</returns>
|
||||
protected virtual CarouselItem GetNextToSelect()
|
||||
{
|
||||
return Items.Skip(lastSelectedIndex).FirstOrDefault(i => !i.Filtered.Value) ??
|
||||
Items.Reverse().Skip(Items.Count - lastSelectedIndex).FirstOrDefault(i => !i.Filtered.Value);
|
||||
if (Items.Count == 0)
|
||||
return null;
|
||||
|
||||
int forwardsIndex = lastSelectedIndex;
|
||||
int backwardsIndex = Math.Min(lastSelectedIndex, Items.Count - 1);
|
||||
|
||||
while (true)
|
||||
{
|
||||
bool hasBackwards = backwardsIndex >= 0 && backwardsIndex < Items.Count;
|
||||
bool hasForwards = forwardsIndex < Items.Count;
|
||||
|
||||
if (!hasBackwards && !hasForwards)
|
||||
return null;
|
||||
|
||||
if (hasForwards && !Items[forwardsIndex].Filtered.Value)
|
||||
return Items[forwardsIndex];
|
||||
|
||||
if (hasBackwards && !Items[backwardsIndex].Filtered.Value)
|
||||
return Items[backwardsIndex];
|
||||
|
||||
forwardsIndex++;
|
||||
backwardsIndex--;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void PerformSelection()
|
||||
|
@ -36,7 +36,7 @@ namespace osu.Game.Screens.Utility
|
||||
|
||||
public readonly Bindable<LatencyVisualMode> VisualMode = new Bindable<LatencyVisualMode>();
|
||||
|
||||
public CursorContainer? MenuCursor { get; private set; }
|
||||
public CursorContainer? Cursor { get; private set; }
|
||||
|
||||
public bool ProvidingUserCursor => IsActiveArea.Value;
|
||||
|
||||
@ -91,7 +91,7 @@ namespace osu.Game.Screens.Utility
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
MenuCursor = new LatencyCursorContainer
|
||||
Cursor = new LatencyCursorContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
@ -105,7 +105,7 @@ namespace osu.Game.Screens.Utility
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
MenuCursor = new LatencyCursorContainer
|
||||
Cursor = new LatencyCursorContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
@ -119,7 +119,7 @@ namespace osu.Game.Screens.Utility
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
MenuCursor = new LatencyCursorContainer
|
||||
Cursor = new LatencyCursorContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
|
Reference in New Issue
Block a user