mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 20:22:55 +08:00
Merge branch 'master' into remove-current-item
This commit is contained in:
commit
2f8a4fd2d0
@ -0,0 +1,49 @@
|
|||||||
|
// 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;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Rulesets.Catch.UI;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Edit
|
||||||
|
{
|
||||||
|
public class CatchEditorPlayfieldAdjustmentContainer : PlayfieldAdjustmentContainer
|
||||||
|
{
|
||||||
|
protected override Container<Drawable> Content => content;
|
||||||
|
private readonly Container content;
|
||||||
|
|
||||||
|
public CatchEditorPlayfieldAdjustmentContainer()
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopCentre;
|
||||||
|
Origin = Anchor.TopCentre;
|
||||||
|
Size = new Vector2(0.8f, 0.9f);
|
||||||
|
|
||||||
|
InternalChild = new ScalingContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
Child = content = new Container { RelativeSizeAxes = Axes.Both },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ScalingContainer : Container
|
||||||
|
{
|
||||||
|
public ScalingContainer()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Y;
|
||||||
|
Width = CatchPlayfield.WIDTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
Scale = new Vector2(Math.Min(Parent.ChildSize.X / CatchPlayfield.WIDTH, Parent.ChildSize.Y / CatchPlayfield.HEIGHT));
|
||||||
|
Height = 1 / Scale.Y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -12,8 +12,10 @@ using osu.Framework.Extensions.EnumExtensions;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Input.Bindings;
|
||||||
using osu.Game.Rulesets.Catch.Objects;
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
using osu.Game.Rulesets.Catch.UI;
|
using osu.Game.Rulesets.Catch.UI;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
@ -37,6 +39,12 @@ namespace osu.Game.Rulesets.Catch.Edit
|
|||||||
|
|
||||||
private InputManager inputManager;
|
private InputManager inputManager;
|
||||||
|
|
||||||
|
private readonly BindableDouble timeRangeMultiplier = new BindableDouble(1)
|
||||||
|
{
|
||||||
|
MinValue = 1,
|
||||||
|
MaxValue = 10,
|
||||||
|
};
|
||||||
|
|
||||||
public CatchHitObjectComposer(CatchRuleset ruleset)
|
public CatchHitObjectComposer(CatchRuleset ruleset)
|
||||||
: base(ruleset)
|
: base(ruleset)
|
||||||
{
|
{
|
||||||
@ -51,7 +59,10 @@ namespace osu.Game.Rulesets.Catch.Edit
|
|||||||
|
|
||||||
LayerBelowRuleset.Add(new PlayfieldBorder
|
LayerBelowRuleset.Add(new PlayfieldBorder
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
Anchor = Anchor.BottomCentre,
|
||||||
|
Origin = Anchor.BottomCentre,
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = CatchPlayfield.HEIGHT,
|
||||||
PlayfieldBorderStyle = { Value = PlayfieldBorderStyle.Corners }
|
PlayfieldBorderStyle = { Value = PlayfieldBorderStyle.Corners }
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -77,8 +88,30 @@ namespace osu.Game.Rulesets.Catch.Edit
|
|||||||
updateDistanceSnapGrid();
|
updateDistanceSnapGrid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
|
||||||
|
{
|
||||||
|
switch (e.Action)
|
||||||
|
{
|
||||||
|
// Note that right now these are hard to use as the default key bindings conflict with existing editor key bindings.
|
||||||
|
// In the future we will want to expose this via UI and potentially change the key bindings to be editor-specific.
|
||||||
|
// May be worth considering standardising "zoom" behaviour with what the timeline uses (ie. alt-wheel) but that may cause new conflicts.
|
||||||
|
case GlobalAction.IncreaseScrollSpeed:
|
||||||
|
this.TransformBindableTo(timeRangeMultiplier, timeRangeMultiplier.Value - 1, 200, Easing.OutQuint);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GlobalAction.DecreaseScrollSpeed:
|
||||||
|
this.TransformBindableTo(timeRangeMultiplier, timeRangeMultiplier.Value + 1, 200, Easing.OutQuint);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.OnPressed(e);
|
||||||
|
}
|
||||||
|
|
||||||
protected override DrawableRuleset<CatchHitObject> CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod> mods = null) =>
|
protected override DrawableRuleset<CatchHitObject> CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod> mods = null) =>
|
||||||
new DrawableCatchEditorRuleset(ruleset, beatmap, mods);
|
new DrawableCatchEditorRuleset(ruleset, beatmap, mods)
|
||||||
|
{
|
||||||
|
TimeRangeMultiplier = { BindTarget = timeRangeMultiplier, }
|
||||||
|
};
|
||||||
|
|
||||||
protected override IReadOnlyList<HitObjectCompositionTool> CompositionTools => new HitObjectCompositionTool[]
|
protected override IReadOnlyList<HitObjectCompositionTool> CompositionTools => new HitObjectCompositionTool[]
|
||||||
{
|
{
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Catch.UI;
|
using osu.Game.Rulesets.Catch.UI;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
@ -13,11 +14,24 @@ namespace osu.Game.Rulesets.Catch.Edit
|
|||||||
{
|
{
|
||||||
public class DrawableCatchEditorRuleset : DrawableCatchRuleset
|
public class DrawableCatchEditorRuleset : DrawableCatchRuleset
|
||||||
{
|
{
|
||||||
|
public readonly BindableDouble TimeRangeMultiplier = new BindableDouble(1);
|
||||||
|
|
||||||
public DrawableCatchEditorRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod> mods = null)
|
public DrawableCatchEditorRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod> mods = null)
|
||||||
: base(ruleset, beatmap, mods)
|
: base(ruleset, beatmap, mods)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
double gamePlayTimeRange = GetTimeRange(Beatmap.Difficulty.ApproachRate);
|
||||||
|
float playfieldStretch = Playfield.DrawHeight / CatchPlayfield.HEIGHT;
|
||||||
|
TimeRange.Value = gamePlayTimeRange * TimeRangeMultiplier.Value * playfieldStretch;
|
||||||
|
}
|
||||||
|
|
||||||
protected override Playfield CreatePlayfield() => new CatchEditorPlayfield(Beatmap.Difficulty);
|
protected override Playfield CreatePlayfield() => new CatchEditorPlayfield(Beatmap.Difficulty);
|
||||||
|
|
||||||
|
public override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new CatchEditorPlayfieldAdjustmentContainer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,17 +19,20 @@ namespace osu.Game.Rulesets.Catch.Mods
|
|||||||
{
|
{
|
||||||
public override LocalisableString Description => @"Use the mouse to control the catcher.";
|
public override LocalisableString Description => @"Use the mouse to control the catcher.";
|
||||||
|
|
||||||
private DrawableRuleset<CatchHitObject> drawableRuleset = null!;
|
private DrawableCatchRuleset drawableRuleset = null!;
|
||||||
|
|
||||||
public void ApplyToDrawableRuleset(DrawableRuleset<CatchHitObject> drawableRuleset)
|
public void ApplyToDrawableRuleset(DrawableRuleset<CatchHitObject> drawableRuleset)
|
||||||
{
|
{
|
||||||
this.drawableRuleset = drawableRuleset;
|
this.drawableRuleset = (DrawableCatchRuleset)drawableRuleset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ApplyToPlayer(Player player)
|
public void ApplyToPlayer(Player player)
|
||||||
{
|
{
|
||||||
if (!drawableRuleset.HasReplayLoaded.Value)
|
if (!drawableRuleset.HasReplayLoaded.Value)
|
||||||
drawableRuleset.Cursor.Add(new MouseInputHelper((CatchPlayfield)drawableRuleset.Playfield));
|
{
|
||||||
|
var catchPlayfield = (CatchPlayfield)drawableRuleset.Playfield;
|
||||||
|
catchPlayfield.CatcherArea.Add(new MouseInputHelper(catchPlayfield.CatcherArea));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MouseInputHelper : Drawable, IKeyBindingHandler<CatchAction>, IRequireHighFrequencyMousePosition
|
private class MouseInputHelper : Drawable, IKeyBindingHandler<CatchAction>, IRequireHighFrequencyMousePosition
|
||||||
@ -38,9 +41,10 @@ namespace osu.Game.Rulesets.Catch.Mods
|
|||||||
|
|
||||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
|
||||||
|
|
||||||
public MouseInputHelper(CatchPlayfield playfield)
|
public MouseInputHelper(CatcherArea catcherArea)
|
||||||
{
|
{
|
||||||
catcherArea = playfield.CatcherArea;
|
this.catcherArea = catcherArea;
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,12 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public const float WIDTH = 512;
|
public const float WIDTH = 512;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The height of the playfield.
|
||||||
|
/// This doesn't include the catcher area.
|
||||||
|
/// </summary>
|
||||||
|
public const float HEIGHT = 384;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The center position of the playfield.
|
/// The center position of the playfield.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
: base(ruleset, beatmap, mods)
|
: base(ruleset, beatmap, mods)
|
||||||
{
|
{
|
||||||
Direction.Value = ScrollingDirection.Down;
|
Direction.Value = ScrollingDirection.Down;
|
||||||
TimeRange.Value = IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.ApproachRate, 1800, 1200, 450);
|
TimeRange.Value = GetTimeRange(beatmap.Difficulty.ApproachRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -42,6 +42,8 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
KeyBindingInputManager.Add(new CatchTouchInputMapper());
|
KeyBindingInputManager.Add(new CatchTouchInputMapper());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected double GetTimeRange(float approachRate) => IBeatmapDifficultyInfo.DifficultyRange(approachRate, 1800, 1200, 450);
|
||||||
|
|
||||||
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new CatchFramedReplayInputHandler(replay);
|
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new CatchFramedReplayInputHandler(replay);
|
||||||
|
|
||||||
protected override ReplayRecorder CreateReplayRecorder(Score score) => new CatchReplayRecorder(score, (CatchPlayfield)Playfield);
|
protected override ReplayRecorder CreateReplayRecorder(Score score) => new CatchReplayRecorder(score, (CatchPlayfield)Playfield);
|
||||||
|
@ -12,6 +12,7 @@ using osu.Framework.Graphics.Shapes;
|
|||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Osu.Beatmaps;
|
using osu.Game.Rulesets.Osu.Beatmaps;
|
||||||
using osu.Game.Rulesets.Osu.Edit;
|
using osu.Game.Rulesets.Osu.Edit;
|
||||||
@ -33,6 +34,9 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
|
|||||||
[Cached(typeof(IBeatSnapProvider))]
|
[Cached(typeof(IBeatSnapProvider))]
|
||||||
private readonly EditorBeatmap editorBeatmap;
|
private readonly EditorBeatmap editorBeatmap;
|
||||||
|
|
||||||
|
[Cached]
|
||||||
|
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Aquamarine);
|
||||||
|
|
||||||
[Cached]
|
[Cached]
|
||||||
private readonly EditorClock editorClock;
|
private readonly EditorClock editorClock;
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Extensions.ObjectExtensions;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
@ -12,6 +13,7 @@ using osu.Game.Rulesets.Objects;
|
|||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Osu.UI;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Tests.Mods
|
namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||||
@ -145,6 +147,10 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
|||||||
|
|
||||||
private bool isBreak() => Player.IsBreakTime.Value;
|
private bool isBreak() => Player.IsBreakTime.Value;
|
||||||
|
|
||||||
private bool cursorAlphaAlmostEquals(float alpha) => Precision.AlmostEquals(Player.DrawableRuleset.Cursor.Alpha, alpha, 0.1f);
|
private OsuPlayfield playfield => (OsuPlayfield)Player.DrawableRuleset.Playfield;
|
||||||
|
|
||||||
|
private bool cursorAlphaAlmostEquals(float alpha) =>
|
||||||
|
Precision.AlmostEquals(playfield.Cursor.AsNonNull().Alpha, alpha, 0.1f) &&
|
||||||
|
Precision.AlmostEquals(playfield.Smoke.Alpha, alpha, 0.1f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,9 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
|
// Give a bit of breathing room around the playfield content.
|
||||||
|
PlayfieldContentContainer.Padding = new MarginPadding(10);
|
||||||
|
|
||||||
LayerBelowRuleset.AddRange(new Drawable[]
|
LayerBelowRuleset.AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
distanceSnapGridContainer = new Container
|
distanceSnapGridContainer = new Container
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Extensions.ObjectExtensions;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
@ -46,7 +47,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
|
|
||||||
public void Update(Playfield playfield)
|
public void Update(Playfield playfield)
|
||||||
{
|
{
|
||||||
var cursorPos = playfield.Cursor.ActiveCursor.DrawPosition;
|
var cursorPos = playfield.Cursor.AsNonNull().ActiveCursor.DrawPosition;
|
||||||
|
|
||||||
foreach (var drawable in playfield.HitObjectContainer.AliveObjects)
|
foreach (var drawable in playfield.HitObjectContainer.AliveObjects)
|
||||||
{
|
{
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// 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;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
@ -9,6 +10,7 @@ using osu.Framework.Utils;
|
|||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.UI;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using osu.Game.Utils;
|
using osu.Game.Utils;
|
||||||
|
|
||||||
@ -33,9 +35,15 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
|
|
||||||
public void Update(Playfield playfield)
|
public void Update(Playfield playfield)
|
||||||
{
|
{
|
||||||
bool shouldAlwaysShowCursor = IsBreakTime.Value || spinnerPeriods.IsInAny(playfield.Clock.CurrentTime);
|
var osuPlayfield = (OsuPlayfield)playfield;
|
||||||
|
Debug.Assert(osuPlayfield.Cursor != null);
|
||||||
|
|
||||||
|
bool shouldAlwaysShowCursor = IsBreakTime.Value || spinnerPeriods.IsInAny(osuPlayfield.Clock.CurrentTime);
|
||||||
float targetAlpha = shouldAlwaysShowCursor ? 1 : ComboBasedAlpha;
|
float targetAlpha = shouldAlwaysShowCursor ? 1 : ComboBasedAlpha;
|
||||||
playfield.Cursor.Alpha = (float)Interpolation.Lerp(playfield.Cursor.Alpha, targetAlpha, Math.Clamp(playfield.Time.Elapsed / TRANSITION_DURATION, 0, 1));
|
float currentAlpha = (float)Interpolation.Lerp(osuPlayfield.Cursor.Alpha, targetAlpha, Math.Clamp(osuPlayfield.Time.Elapsed / TRANSITION_DURATION, 0, 1));
|
||||||
|
|
||||||
|
osuPlayfield.Cursor.Alpha = currentAlpha;
|
||||||
|
osuPlayfield.Smoke.Alpha = currentAlpha;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Extensions.ObjectExtensions;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
@ -45,7 +46,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
|
|
||||||
public void Update(Playfield playfield)
|
public void Update(Playfield playfield)
|
||||||
{
|
{
|
||||||
var cursorPos = playfield.Cursor.ActiveCursor.DrawPosition;
|
var cursorPos = playfield.Cursor.AsNonNull().ActiveCursor.DrawPosition;
|
||||||
|
|
||||||
foreach (var drawable in playfield.HitObjectContainer.AliveObjects)
|
foreach (var drawable in playfield.HitObjectContainer.AliveObjects)
|
||||||
{
|
{
|
||||||
|
@ -331,7 +331,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
{
|
{
|
||||||
base.UpdateHitStateTransforms(state);
|
base.UpdateHitStateTransforms(state);
|
||||||
|
|
||||||
const float fade_out_time = 450;
|
const float fade_out_time = 240;
|
||||||
|
|
||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
@ -341,7 +341,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.FadeOut(fade_out_time, Easing.OutQuint).Expire();
|
this.FadeOut(fade_out_time).Expire();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => SliderBody?.ReceivePositionalInputAt(screenSpacePos) ?? base.ReceivePositionalInputAt(screenSpacePos);
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => SliderBody?.ReceivePositionalInputAt(screenSpacePos) ?? base.ReceivePositionalInputAt(screenSpacePos);
|
||||||
|
@ -57,7 +57,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly IBindable<double> SpinsPerMinute = new BindableDouble();
|
public readonly IBindable<double> SpinsPerMinute = new BindableDouble();
|
||||||
|
|
||||||
private const double fade_out_duration = 160;
|
private const double fade_out_duration = 240;
|
||||||
|
|
||||||
public DrawableSpinner()
|
public DrawableSpinner()
|
||||||
: this(null)
|
: this(null)
|
||||||
|
@ -75,6 +75,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon
|
|||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
JudgementText
|
JudgementText
|
||||||
|
.FadeInFromZero(300, Easing.OutQuint)
|
||||||
.ScaleTo(Vector2.One)
|
.ScaleTo(Vector2.One)
|
||||||
.ScaleTo(new Vector2(1.2f), 1800, Easing.OutQuint);
|
.ScaleTo(new Vector2(1.2f), 1800, Easing.OutQuint);
|
||||||
break;
|
break;
|
||||||
@ -96,7 +97,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon
|
|||||||
ringExplosion?.PlayAnimation();
|
ringExplosion?.PlayAnimation();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Drawable? GetAboveHitObjectsProxiedContent() => null;
|
public Drawable? GetAboveHitObjectsProxiedContent() => JudgementText.CreateProxy();
|
||||||
|
|
||||||
private class RingExplosion : CompositeDrawable
|
private class RingExplosion : CompositeDrawable
|
||||||
{
|
{
|
||||||
|
@ -134,10 +134,10 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
case ArmedState.Hit:
|
case ArmedState.Hit:
|
||||||
CircleSprite.FadeOut(legacy_fade_duration, Easing.Out);
|
CircleSprite.FadeOut(legacy_fade_duration);
|
||||||
CircleSprite.ScaleTo(1.4f, legacy_fade_duration, Easing.Out);
|
CircleSprite.ScaleTo(1.4f, legacy_fade_duration, Easing.Out);
|
||||||
|
|
||||||
OverlaySprite.FadeOut(legacy_fade_duration, Easing.Out);
|
OverlaySprite.FadeOut(legacy_fade_duration);
|
||||||
OverlaySprite.ScaleTo(1.4f, legacy_fade_duration, Easing.Out);
|
OverlaySprite.ScaleTo(1.4f, legacy_fade_duration, Easing.Out);
|
||||||
|
|
||||||
if (hasNumber)
|
if (hasNumber)
|
||||||
@ -146,11 +146,11 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
|
|
||||||
if (legacyVersion >= 2.0m)
|
if (legacyVersion >= 2.0m)
|
||||||
// legacy skins of version 2.0 and newer only apply very short fade out to the number piece.
|
// legacy skins of version 2.0 and newer only apply very short fade out to the number piece.
|
||||||
hitCircleText.FadeOut(legacy_fade_duration / 4, Easing.Out);
|
hitCircleText.FadeOut(legacy_fade_duration / 4);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// old skins scale and fade it normally along other pieces.
|
// old skins scale and fade it normally along other pieces.
|
||||||
hitCircleText.FadeOut(legacy_fade_duration, Easing.Out);
|
hitCircleText.FadeOut(legacy_fade_duration);
|
||||||
hitCircleText.ScaleTo(1.4f, legacy_fade_duration, Easing.Out);
|
hitCircleText.ScaleTo(1.4f, legacy_fade_duration, Easing.Out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,8 +107,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
using (BeginAbsoluteSequence(spinner.StartTime - spinner.TimePreempt))
|
using (BeginAbsoluteSequence(spinner.StartTime - spinner.TimePreempt))
|
||||||
this.FadeOut();
|
this.FadeOut();
|
||||||
|
|
||||||
using (BeginAbsoluteSequence(spinner.StartTime - spinner.TimeFadeIn / 2))
|
using (BeginAbsoluteSequence(spinner.StartTime - spinner.TimeFadeIn))
|
||||||
this.FadeInFromZero(spinner.TimeFadeIn / 2);
|
this.FadeInFromZero(spinner.TimeFadeIn);
|
||||||
|
|
||||||
using (BeginAbsoluteSequence(spinner.StartTime - spinner.TimePreempt))
|
using (BeginAbsoluteSequence(spinner.StartTime - spinner.TimePreempt))
|
||||||
{
|
{
|
||||||
|
@ -65,6 +65,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
{
|
{
|
||||||
spin = new Sprite
|
spin = new Sprite
|
||||||
{
|
{
|
||||||
|
Alpha = 0,
|
||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Texture = source.GetTexture("spinner-spin"),
|
Texture = source.GetTexture("spinner-spin"),
|
||||||
@ -82,7 +83,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
},
|
},
|
||||||
bonusCounter = new LegacySpriteText(LegacyFont.Score)
|
bonusCounter = new LegacySpriteText(LegacyFont.Score)
|
||||||
{
|
{
|
||||||
Alpha = 0f,
|
Alpha = 0,
|
||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Scale = new Vector2(SPRITE_SCALE),
|
Scale = new Vector2(SPRITE_SCALE),
|
||||||
@ -179,6 +180,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
spmCounter.MoveToOffset(new Vector2(0, -spm_hide_offset), d.HitObject.TimeFadeIn, Easing.Out);
|
spmCounter.MoveToOffset(new Vector2(0, -spm_hide_offset), d.HitObject.TimeFadeIn, Easing.Out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using (BeginAbsoluteSequence(d.HitObject.StartTime - d.HitObject.TimeFadeIn / 2))
|
||||||
|
spin.FadeInFromZero(d.HitObject.TimeFadeIn / 2);
|
||||||
|
|
||||||
using (BeginAbsoluteSequence(d.HitObject.StartTime))
|
using (BeginAbsoluteSequence(d.HitObject.StartTime))
|
||||||
ApproachCircle?.ScaleTo(SPRITE_SCALE * 0.1f, d.HitObject.Duration);
|
ApproachCircle?.ScaleTo(SPRITE_SCALE * 0.1f, d.HitObject.Duration);
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ using osu.Framework.Graphics.Rendering.Vertices;
|
|||||||
using osu.Framework.Graphics.Shaders;
|
using osu.Framework.Graphics.Shaders;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Utils;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
@ -185,6 +186,8 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
private float radius;
|
private float radius;
|
||||||
private Vector2 drawSize;
|
private Vector2 drawSize;
|
||||||
private Texture? texture;
|
private Texture? texture;
|
||||||
|
private int rotationSeed;
|
||||||
|
private int rotationIndex;
|
||||||
|
|
||||||
// anim calculation vars (color, scale, direction)
|
// anim calculation vars (color, scale, direction)
|
||||||
private double initialFadeOutDurationTrunc;
|
private double initialFadeOutDurationTrunc;
|
||||||
@ -194,8 +197,6 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
private double reFadeInTime;
|
private double reFadeInTime;
|
||||||
private double finalFadeOutTime;
|
private double finalFadeOutTime;
|
||||||
|
|
||||||
private Random rotationRNG = new Random();
|
|
||||||
|
|
||||||
public SmokeDrawNode(ITexturedShaderDrawable source)
|
public SmokeDrawNode(ITexturedShaderDrawable source)
|
||||||
: base(source)
|
: base(source)
|
||||||
{
|
{
|
||||||
@ -216,7 +217,7 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
SmokeEndTime = Source.smokeEndTime;
|
SmokeEndTime = Source.smokeEndTime;
|
||||||
CurrentTime = Source.Clock.CurrentTime;
|
CurrentTime = Source.Clock.CurrentTime;
|
||||||
|
|
||||||
rotationRNG = new Random(Source.rotationSeed);
|
rotationSeed = Source.rotationSeed;
|
||||||
|
|
||||||
initialFadeOutDurationTrunc = Math.Min(initial_fade_out_duration, SmokeEndTime - SmokeStartTime);
|
initialFadeOutDurationTrunc = Math.Min(initial_fade_out_duration, SmokeEndTime - SmokeStartTime);
|
||||||
firstVisiblePointTime = SmokeEndTime - initialFadeOutDurationTrunc;
|
firstVisiblePointTime = SmokeEndTime - initialFadeOutDurationTrunc;
|
||||||
@ -233,6 +234,8 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
if (points.Count == 0)
|
if (points.Count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
rotationIndex = 0;
|
||||||
|
|
||||||
quadBatch ??= renderer.CreateQuadBatch<TexturedVertex2D>(max_point_count / 10, 10);
|
quadBatch ??= renderer.CreateQuadBatch<TexturedVertex2D>(max_point_count / 10, 10);
|
||||||
texture ??= renderer.WhitePixel;
|
texture ??= renderer.WhitePixel;
|
||||||
RectangleF textureRect = texture.GetTextureRect();
|
RectangleF textureRect = texture.GetTextureRect();
|
||||||
@ -311,7 +314,7 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
return new Vector2(MathF.Sin(angle), -MathF.Cos(angle));
|
return new Vector2(MathF.Sin(angle), -MathF.Cos(angle));
|
||||||
}
|
}
|
||||||
|
|
||||||
private float nextRotation() => max_rotation * ((float)rotationRNG.NextDouble() * 2 - 1);
|
private float nextRotation() => max_rotation * (StatelessRNG.NextSingle(rotationSeed, rotationIndex++) * 2 - 1);
|
||||||
|
|
||||||
private void drawPointQuad(SmokePoint point, RectangleF textureRect)
|
private void drawPointQuad(SmokePoint point, RectangleF textureRect)
|
||||||
{
|
{
|
||||||
|
@ -36,6 +36,7 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
private readonly ProxyContainer spinnerProxies;
|
private readonly ProxyContainer spinnerProxies;
|
||||||
private readonly JudgementContainer<DrawableOsuJudgement> judgementLayer;
|
private readonly JudgementContainer<DrawableOsuJudgement> judgementLayer;
|
||||||
|
|
||||||
|
public SmokeContainer Smoke { get; }
|
||||||
public FollowPointRenderer FollowPoints { get; }
|
public FollowPointRenderer FollowPoints { get; }
|
||||||
|
|
||||||
public static readonly Vector2 BASE_SIZE = new Vector2(512, 384);
|
public static readonly Vector2 BASE_SIZE = new Vector2(512, 384);
|
||||||
@ -54,7 +55,7 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
playfieldBorder = new PlayfieldBorder { RelativeSizeAxes = Axes.Both },
|
playfieldBorder = new PlayfieldBorder { RelativeSizeAxes = Axes.Both },
|
||||||
new SmokeContainer { RelativeSizeAxes = Axes.Both },
|
Smoke = new SmokeContainer { RelativeSizeAxes = Axes.Both },
|
||||||
spinnerProxies = new ProxyContainer { RelativeSizeAxes = Axes.Both },
|
spinnerProxies = new ProxyContainer { RelativeSizeAxes = Axes.Both },
|
||||||
FollowPoints = new FollowPointRenderer { RelativeSizeAxes = Axes.Both },
|
FollowPoints = new FollowPointRenderer { RelativeSizeAxes = Axes.Both },
|
||||||
judgementLayer = new JudgementContainer<DrawableOsuJudgement> { RelativeSizeAxes = Axes.Both },
|
judgementLayer = new JudgementContainer<DrawableOsuJudgement> { RelativeSizeAxes = Axes.Both },
|
||||||
|
@ -244,7 +244,10 @@ namespace osu.Game.Tests.Visual.Background
|
|||||||
public void TestResumeFromPlayer()
|
public void TestResumeFromPlayer()
|
||||||
{
|
{
|
||||||
performFullSetup();
|
performFullSetup();
|
||||||
AddStep("Move mouse to Visual Settings", () => InputManager.MoveMouseTo(playerLoader.VisualSettingsPos));
|
AddStep("Move mouse to Visual Settings location", () => InputManager.MoveMouseTo(playerLoader.ScreenSpaceDrawQuad.TopRight
|
||||||
|
+ new Vector2(-playerLoader.VisualSettingsPos.ScreenSpaceDrawQuad.Width,
|
||||||
|
playerLoader.VisualSettingsPos.ScreenSpaceDrawQuad.Height / 2
|
||||||
|
)));
|
||||||
AddStep("Resume PlayerLoader", () => player.Restart());
|
AddStep("Resume PlayerLoader", () => player.Restart());
|
||||||
AddUntilStep("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied());
|
AddUntilStep("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied());
|
||||||
AddStep("Move mouse to center of screen", () => InputManager.MoveMouseTo(playerLoader.ScreenPos));
|
AddStep("Move mouse to center of screen", () => InputManager.MoveMouseTo(playerLoader.ScreenPos));
|
||||||
|
@ -4,8 +4,10 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Screens.Edit.Components.RadioButtons;
|
using osu.Game.Screens.Edit.Components.RadioButtons;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Editing
|
namespace osu.Game.Tests.Visual.Editing
|
||||||
@ -13,6 +15,9 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestSceneEditorComposeRadioButtons : OsuTestScene
|
public class TestSceneEditorComposeRadioButtons : OsuTestScene
|
||||||
{
|
{
|
||||||
|
[Cached]
|
||||||
|
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Aquamarine);
|
||||||
|
|
||||||
public TestSceneEditorComposeRadioButtons()
|
public TestSceneEditorComposeRadioButtons()
|
||||||
{
|
{
|
||||||
EditorRadioButtonCollection collection;
|
EditorRadioButtonCollection collection;
|
||||||
|
@ -148,10 +148,6 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
});
|
});
|
||||||
|
|
||||||
AddAssert("no circles placed", () => editorBeatmap.HitObjects.Count == 0);
|
AddAssert("no circles placed", () => editorBeatmap.HitObjects.Count == 0);
|
||||||
|
|
||||||
AddStep("place circle", () => InputManager.Click(MouseButton.Left));
|
|
||||||
|
|
||||||
AddAssert("circle placed", () => editorBeatmap.HitObjects.Count == 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -55,7 +55,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new MenuCursor()
|
new MenuCursorContainer()
|
||||||
};
|
};
|
||||||
|
|
||||||
scrollContainer.Add(innerBox = new Box
|
scrollContainer.Add(innerBox = new Box
|
||||||
|
@ -25,6 +25,7 @@ using osu.Game.Rulesets.Mods;
|
|||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using osu.Game.Screens.Menu;
|
using osu.Game.Screens.Menu;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
using osuTK.Input;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Navigation
|
namespace osu.Game.Tests.Visual.Navigation
|
||||||
{
|
{
|
||||||
@ -79,6 +80,16 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private OsuGameBase gameBase { get; set; }
|
private OsuGameBase gameBase { get; set; }
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestCursorHidesWhenIdle()
|
||||||
|
{
|
||||||
|
AddStep("click mouse", () => InputManager.Click(MouseButton.Left));
|
||||||
|
AddUntilStep("wait until idle", () => Game.IsIdle.Value);
|
||||||
|
AddUntilStep("menu cursor hidden", () => Game.GlobalCursorDisplay.MenuCursor.ActiveCursor.Alpha == 0);
|
||||||
|
AddStep("click mouse", () => InputManager.Click(MouseButton.Left));
|
||||||
|
AddUntilStep("menu cursor shown", () => Game.GlobalCursorDisplay.MenuCursor.ActiveCursor.Alpha == 1);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestNullRulesetHandled()
|
public void TestNullRulesetHandled()
|
||||||
{
|
{
|
||||||
|
@ -15,6 +15,7 @@ using osu.Game.Graphics.Cursor;
|
|||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
using osuTK.Input;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.UserInterface
|
namespace osu.Game.Tests.Visual.UserInterface
|
||||||
{
|
{
|
||||||
@ -81,25 +82,24 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
};
|
};
|
||||||
|
|
||||||
AddToggleStep("Smooth transitions", b => cursorBoxes.ForEach(box => box.SmoothTransition = b));
|
AddToggleStep("Smooth transitions", b => cursorBoxes.ForEach(box => box.SmoothTransition = b));
|
||||||
|
|
||||||
testUserCursor();
|
|
||||||
testLocalCursor();
|
|
||||||
testUserCursorOverride();
|
|
||||||
testMultipleLocalCursors();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void SetUp() => Schedule(moveOut);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// -- Green Box --
|
/// -- Green Box --
|
||||||
/// Tests whether hovering in and out of a drawable that provides the user cursor (green)
|
/// Tests whether hovering in and out of a drawable that provides the user cursor (green)
|
||||||
/// results in the correct visibility state for that cursor.
|
/// results in the correct visibility state for that cursor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void testUserCursor()
|
[Test]
|
||||||
|
public void TestUserCursor()
|
||||||
{
|
{
|
||||||
AddStep("Move to green area", () => InputManager.MoveMouseTo(cursorBoxes[0]));
|
AddStep("Move to green area", () => InputManager.MoveMouseTo(cursorBoxes[0]));
|
||||||
AddAssert("Check green cursor visible", () => checkVisible(cursorBoxes[0].MenuCursor));
|
AddAssert("Check green cursor visible", () => checkVisible(cursorBoxes[0].Cursor));
|
||||||
AddAssert("Check green cursor at mouse", () => checkAtMouse(cursorBoxes[0].MenuCursor));
|
AddAssert("Check green cursor at mouse", () => checkAtMouse(cursorBoxes[0].Cursor));
|
||||||
AddStep("Move out", moveOut);
|
AddStep("Move out", moveOut);
|
||||||
AddAssert("Check green cursor invisible", () => !checkVisible(cursorBoxes[0].MenuCursor));
|
AddAssert("Check green cursor invisible", () => !checkVisible(cursorBoxes[0].Cursor));
|
||||||
AddAssert("Check global cursor visible", () => checkVisible(globalCursorDisplay.MenuCursor));
|
AddAssert("Check global cursor visible", () => checkVisible(globalCursorDisplay.MenuCursor));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,15 +108,16 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
/// Tests whether hovering in and out of a drawable that provides a local cursor (purple)
|
/// Tests whether hovering in and out of a drawable that provides a local cursor (purple)
|
||||||
/// results in the correct visibility and state for that cursor.
|
/// results in the correct visibility and state for that cursor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void testLocalCursor()
|
[Test]
|
||||||
|
public void TestLocalCursor()
|
||||||
{
|
{
|
||||||
AddStep("Move to purple area", () => InputManager.MoveMouseTo(cursorBoxes[3]));
|
AddStep("Move to purple area", () => InputManager.MoveMouseTo(cursorBoxes[3]));
|
||||||
AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].MenuCursor));
|
AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].Cursor));
|
||||||
AddAssert("Check purple cursor at mouse", () => checkAtMouse(cursorBoxes[3].MenuCursor));
|
AddAssert("Check purple cursor at mouse", () => checkAtMouse(cursorBoxes[3].Cursor));
|
||||||
AddAssert("Check global cursor visible", () => checkVisible(globalCursorDisplay.MenuCursor));
|
AddAssert("Check global cursor visible", () => checkVisible(globalCursorDisplay.MenuCursor));
|
||||||
AddAssert("Check global cursor at mouse", () => checkAtMouse(globalCursorDisplay.MenuCursor));
|
AddAssert("Check global cursor at mouse", () => checkAtMouse(globalCursorDisplay.MenuCursor));
|
||||||
AddStep("Move out", moveOut);
|
AddStep("Move out", moveOut);
|
||||||
AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].MenuCursor));
|
AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].Cursor));
|
||||||
AddAssert("Check global cursor visible", () => checkVisible(globalCursorDisplay.MenuCursor));
|
AddAssert("Check global cursor visible", () => checkVisible(globalCursorDisplay.MenuCursor));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,47 +126,96 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
/// Tests whether overriding a user cursor (green) with another user cursor (blue)
|
/// Tests whether overriding a user cursor (green) with another user cursor (blue)
|
||||||
/// results in the correct visibility and states for the cursors.
|
/// results in the correct visibility and states for the cursors.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void testUserCursorOverride()
|
[Test]
|
||||||
|
public void TestUserCursorOverride()
|
||||||
{
|
{
|
||||||
AddStep("Move to blue-green boundary", () => InputManager.MoveMouseTo(cursorBoxes[1].ScreenSpaceDrawQuad.BottomRight - new Vector2(10)));
|
AddStep("Move to blue-green boundary", () => InputManager.MoveMouseTo(cursorBoxes[1].ScreenSpaceDrawQuad.BottomRight - new Vector2(10)));
|
||||||
AddAssert("Check blue cursor visible", () => checkVisible(cursorBoxes[1].MenuCursor));
|
AddAssert("Check blue cursor visible", () => checkVisible(cursorBoxes[1].Cursor));
|
||||||
AddAssert("Check green cursor invisible", () => !checkVisible(cursorBoxes[0].MenuCursor));
|
AddAssert("Check green cursor invisible", () => !checkVisible(cursorBoxes[0].Cursor));
|
||||||
AddAssert("Check blue cursor at mouse", () => checkAtMouse(cursorBoxes[1].MenuCursor));
|
AddAssert("Check blue cursor at mouse", () => checkAtMouse(cursorBoxes[1].Cursor));
|
||||||
AddStep("Move out", moveOut);
|
AddStep("Move out", moveOut);
|
||||||
AddAssert("Check blue cursor not visible", () => !checkVisible(cursorBoxes[1].MenuCursor));
|
AddAssert("Check blue cursor not visible", () => !checkVisible(cursorBoxes[1].Cursor));
|
||||||
AddAssert("Check green cursor not visible", () => !checkVisible(cursorBoxes[0].MenuCursor));
|
AddAssert("Check green cursor not visible", () => !checkVisible(cursorBoxes[0].Cursor));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// -- Yellow-Purple Box Boundary --
|
/// -- Yellow-Purple Box Boundary --
|
||||||
/// Tests whether multiple local cursors (purple + yellow) may be visible and at the mouse position at the same time.
|
/// Tests whether multiple local cursors (purple + yellow) may be visible and at the mouse position at the same time.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void testMultipleLocalCursors()
|
[Test]
|
||||||
|
public void TestMultipleLocalCursors()
|
||||||
{
|
{
|
||||||
AddStep("Move to yellow-purple boundary", () => InputManager.MoveMouseTo(cursorBoxes[5].ScreenSpaceDrawQuad.BottomRight - new Vector2(10)));
|
AddStep("Move to yellow-purple boundary", () => InputManager.MoveMouseTo(cursorBoxes[5].ScreenSpaceDrawQuad.BottomRight - new Vector2(10)));
|
||||||
AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].MenuCursor));
|
AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].Cursor));
|
||||||
AddAssert("Check purple cursor at mouse", () => checkAtMouse(cursorBoxes[3].MenuCursor));
|
AddAssert("Check purple cursor at mouse", () => checkAtMouse(cursorBoxes[3].Cursor));
|
||||||
AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].MenuCursor));
|
AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].Cursor));
|
||||||
AddAssert("Check yellow cursor at mouse", () => checkAtMouse(cursorBoxes[5].MenuCursor));
|
AddAssert("Check yellow cursor at mouse", () => checkAtMouse(cursorBoxes[5].Cursor));
|
||||||
AddStep("Move out", moveOut);
|
AddStep("Move out", moveOut);
|
||||||
AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].MenuCursor));
|
AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].Cursor));
|
||||||
AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].MenuCursor));
|
AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].Cursor));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// -- Yellow-Blue Box Boundary --
|
/// -- Yellow-Blue Box Boundary --
|
||||||
/// Tests whether a local cursor (yellow) may be displayed along with a user cursor override (blue).
|
/// Tests whether a local cursor (yellow) may be displayed along with a user cursor override (blue).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void testUserOverrideWithLocal()
|
[Test]
|
||||||
|
public void TestUserOverrideWithLocal()
|
||||||
{
|
{
|
||||||
AddStep("Move to yellow-blue boundary", () => InputManager.MoveMouseTo(cursorBoxes[5].ScreenSpaceDrawQuad.TopRight - new Vector2(10)));
|
AddStep("Move to yellow-blue boundary", () => InputManager.MoveMouseTo(cursorBoxes[5].ScreenSpaceDrawQuad.TopRight - new Vector2(10, 0)));
|
||||||
AddAssert("Check blue cursor visible", () => checkVisible(cursorBoxes[1].MenuCursor));
|
AddAssert("Check blue cursor visible", () => checkVisible(cursorBoxes[1].Cursor));
|
||||||
AddAssert("Check blue cursor at mouse", () => checkAtMouse(cursorBoxes[1].MenuCursor));
|
AddAssert("Check blue cursor at mouse", () => checkAtMouse(cursorBoxes[1].Cursor));
|
||||||
AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].MenuCursor));
|
AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].Cursor));
|
||||||
AddAssert("Check yellow cursor at mouse", () => checkAtMouse(cursorBoxes[5].MenuCursor));
|
AddAssert("Check yellow cursor at mouse", () => checkAtMouse(cursorBoxes[5].Cursor));
|
||||||
AddStep("Move out", moveOut);
|
AddStep("Move out", moveOut);
|
||||||
AddAssert("Check blue cursor invisible", () => !checkVisible(cursorBoxes[1].MenuCursor));
|
AddAssert("Check blue cursor invisible", () => !checkVisible(cursorBoxes[1].Cursor));
|
||||||
AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].MenuCursor));
|
AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].Cursor));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ensures non-mouse input hides global cursor on a "local cursor" area (which doesn't hide global cursor).
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public void TestKeyboardLocalCursor([Values] bool clickToShow)
|
||||||
|
{
|
||||||
|
AddStep("Move to purple area", () => InputManager.MoveMouseTo(cursorBoxes[3].ScreenSpaceDrawQuad.Centre + new Vector2(10, 0)));
|
||||||
|
AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].Cursor));
|
||||||
|
AddAssert("Check global cursor alpha is 1", () => globalCursorDisplay.MenuCursor.Alpha == 1);
|
||||||
|
|
||||||
|
AddStep("Press key", () => InputManager.Key(Key.A));
|
||||||
|
AddAssert("Check purple cursor still visible", () => checkVisible(cursorBoxes[3].Cursor));
|
||||||
|
AddUntilStep("Check global cursor alpha is 0", () => globalCursorDisplay.MenuCursor.ActiveCursor.Alpha == 0);
|
||||||
|
|
||||||
|
if (clickToShow)
|
||||||
|
AddStep("Click mouse", () => InputManager.Click(MouseButton.Left));
|
||||||
|
else
|
||||||
|
AddStep("Move mouse", () => InputManager.MoveMouseTo(InputManager.CurrentState.Mouse.Position + Vector2.One));
|
||||||
|
|
||||||
|
AddAssert("Check purple cursor still visible", () => checkVisible(cursorBoxes[3].Cursor));
|
||||||
|
AddUntilStep("Check global cursor alpha is 1", () => globalCursorDisplay.MenuCursor.ActiveCursor.Alpha == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ensures mouse input after non-mouse input doesn't show global cursor on a "user cursor" area (which hides global cursor).
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public void TestKeyboardUserCursor([Values] bool clickToShow)
|
||||||
|
{
|
||||||
|
AddStep("Move to green area", () => InputManager.MoveMouseTo(cursorBoxes[0]));
|
||||||
|
AddAssert("Check green cursor visible", () => checkVisible(cursorBoxes[0].Cursor));
|
||||||
|
AddAssert("Check global cursor alpha is 0", () => !checkVisible(globalCursorDisplay.MenuCursor) && globalCursorDisplay.MenuCursor.ActiveCursor.Alpha == 0);
|
||||||
|
|
||||||
|
AddStep("Press key", () => InputManager.Key(Key.A));
|
||||||
|
AddAssert("Check green cursor still visible", () => checkVisible(cursorBoxes[0].Cursor));
|
||||||
|
AddAssert("Check global cursor alpha is still 0", () => !checkVisible(globalCursorDisplay.MenuCursor) && globalCursorDisplay.MenuCursor.ActiveCursor.Alpha == 0);
|
||||||
|
|
||||||
|
if (clickToShow)
|
||||||
|
AddStep("Click mouse", () => InputManager.Click(MouseButton.Left));
|
||||||
|
else
|
||||||
|
AddStep("Move mouse", () => InputManager.MoveMouseTo(InputManager.CurrentState.Mouse.Position + Vector2.One));
|
||||||
|
|
||||||
|
AddAssert("Check green cursor still visible", () => checkVisible(cursorBoxes[0].Cursor));
|
||||||
|
AddAssert("Check global cursor alpha is still 0", () => !checkVisible(globalCursorDisplay.MenuCursor) && globalCursorDisplay.MenuCursor.ActiveCursor.Alpha == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -191,7 +241,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
{
|
{
|
||||||
public bool SmoothTransition;
|
public bool SmoothTransition;
|
||||||
|
|
||||||
public CursorContainer MenuCursor { get; }
|
public CursorContainer Cursor { get; }
|
||||||
public bool ProvidingUserCursor { get; }
|
public bool ProvidingUserCursor { get; }
|
||||||
|
|
||||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => base.ReceivePositionalInputAt(screenSpacePos) || (SmoothTransition && !ProvidingUserCursor);
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => base.ReceivePositionalInputAt(screenSpacePos) || (SmoothTransition && !ProvidingUserCursor);
|
||||||
@ -218,7 +268,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Text = providesUserCursor ? "User cursor" : "Local cursor"
|
Text = providesUserCursor ? "User cursor" : "Local cursor"
|
||||||
},
|
},
|
||||||
MenuCursor = new TestCursorContainer
|
Cursor = new TestCursorContainer
|
||||||
{
|
{
|
||||||
State = { Value = providesUserCursor ? Visibility.Hidden : Visibility.Visible },
|
State = { Value = providesUserCursor ? Visibility.Hidden : Visibility.Visible },
|
||||||
}
|
}
|
||||||
|
@ -5,12 +5,14 @@
|
|||||||
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Graphics.UserInterfaceV2;
|
using osu.Game.Graphics.UserInterfaceV2;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Overlays.Settings;
|
using osu.Game.Overlays.Settings;
|
||||||
|
using osuTK;
|
||||||
using osuTK.Input;
|
using osuTK.Input;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.UserInterface
|
namespace osu.Game.Tests.Visual.UserInterface
|
||||||
@ -20,11 +22,17 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
{
|
{
|
||||||
private SettingsToolboxGroup group;
|
private SettingsToolboxGroup group;
|
||||||
|
|
||||||
|
[Cached]
|
||||||
|
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void SetUp() => Schedule(() =>
|
public void SetUp() => Schedule(() =>
|
||||||
{
|
{
|
||||||
Child = group = new SettingsToolboxGroup("example")
|
Child = group = new SettingsToolboxGroup("example")
|
||||||
{
|
{
|
||||||
|
Scale = new Vector2(3),
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new RoundedButton
|
new RoundedButton
|
||||||
|
@ -13,7 +13,7 @@ using osu.Game.Configuration;
|
|||||||
namespace osu.Game.Graphics.Cursor
|
namespace osu.Game.Graphics.Cursor
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A container which provides the main <see cref="Cursor.MenuCursor"/>.
|
/// A container which provides the main <see cref="MenuCursorContainer"/>.
|
||||||
/// Also handles cases where a more localised cursor is provided by another component (via <see cref="IProvideCursor"/>).
|
/// Also handles cases where a more localised cursor is provided by another component (via <see cref="IProvideCursor"/>).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class GlobalCursorDisplay : Container, IProvideCursor
|
public class GlobalCursorDisplay : Container, IProvideCursor
|
||||||
@ -23,7 +23,9 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal bool ShowCursor = true;
|
internal bool ShowCursor = true;
|
||||||
|
|
||||||
public CursorContainer MenuCursor { get; }
|
CursorContainer IProvideCursor.Cursor => MenuCursor;
|
||||||
|
|
||||||
|
public MenuCursorContainer MenuCursor { get; }
|
||||||
|
|
||||||
public bool ProvidingUserCursor => true;
|
public bool ProvidingUserCursor => true;
|
||||||
|
|
||||||
@ -42,8 +44,8 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
{
|
{
|
||||||
AddRangeInternal(new Drawable[]
|
AddRangeInternal(new Drawable[]
|
||||||
{
|
{
|
||||||
MenuCursor = new MenuCursor { State = { Value = Visibility.Hidden } },
|
Content = new Container { RelativeSizeAxes = Axes.Both },
|
||||||
Content = new Container { RelativeSizeAxes = Axes.Both }
|
MenuCursor = new MenuCursorContainer { State = { Value = Visibility.Hidden } }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,7 +66,7 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
|
|
||||||
if (!hasValidInput || !ShowCursor)
|
if (!hasValidInput || !ShowCursor)
|
||||||
{
|
{
|
||||||
currentOverrideProvider?.MenuCursor?.Hide();
|
currentOverrideProvider?.Cursor?.Hide();
|
||||||
currentOverrideProvider = null;
|
currentOverrideProvider = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -83,8 +85,8 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
if (currentOverrideProvider == newOverrideProvider)
|
if (currentOverrideProvider == newOverrideProvider)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
currentOverrideProvider?.MenuCursor?.Hide();
|
currentOverrideProvider?.Cursor?.Hide();
|
||||||
newOverrideProvider.MenuCursor?.Show();
|
newOverrideProvider.Cursor?.Show();
|
||||||
|
|
||||||
currentOverrideProvider = newOverrideProvider;
|
currentOverrideProvider = newOverrideProvider;
|
||||||
}
|
}
|
||||||
|
@ -17,10 +17,10 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
/// The cursor provided by this <see cref="IDrawable"/>.
|
/// The cursor provided by this <see cref="IDrawable"/>.
|
||||||
/// May be null if no cursor should be visible.
|
/// May be null if no cursor should be visible.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
CursorContainer MenuCursor { get; }
|
CursorContainer Cursor { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether <see cref="MenuCursor"/> should be displayed as the singular user cursor. This will temporarily hide any other user cursor.
|
/// Whether <see cref="Cursor"/> should be displayed as the singular user cursor. This will temporarily hide any other user cursor.
|
||||||
/// This value is checked every frame and may be used to control whether multiple cursors are displayed (e.g. watching replays).
|
/// This value is checked every frame and may be used to control whether multiple cursors are displayed (e.g. watching replays).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool ProvidingUserCursor { get; }
|
bool ProvidingUserCursor { get; }
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
// 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.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using JetBrains.Annotations;
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Audio.Sample;
|
using osu.Framework.Audio.Sample;
|
||||||
@ -21,24 +18,28 @@ using osuTK;
|
|||||||
|
|
||||||
namespace osu.Game.Graphics.Cursor
|
namespace osu.Game.Graphics.Cursor
|
||||||
{
|
{
|
||||||
public class MenuCursor : CursorContainer
|
public class MenuCursorContainer : CursorContainer
|
||||||
{
|
{
|
||||||
private readonly IBindable<bool> screenshotCursorVisibility = new Bindable<bool>(true);
|
private readonly IBindable<bool> screenshotCursorVisibility = new Bindable<bool>(true);
|
||||||
public override bool IsPresent => screenshotCursorVisibility.Value && base.IsPresent;
|
public override bool IsPresent => screenshotCursorVisibility.Value && base.IsPresent;
|
||||||
|
|
||||||
protected override Drawable CreateCursor() => activeCursor = new Cursor();
|
protected override Drawable CreateCursor() => activeCursor = new Cursor();
|
||||||
|
|
||||||
private Cursor activeCursor;
|
private Cursor activeCursor = null!;
|
||||||
|
|
||||||
private Bindable<bool> cursorRotate;
|
|
||||||
private DragRotationState dragRotationState;
|
private DragRotationState dragRotationState;
|
||||||
private Vector2 positionMouseDown;
|
private Vector2 positionMouseDown;
|
||||||
|
|
||||||
private Sample tapSample;
|
|
||||||
private Vector2 lastMovePosition;
|
private Vector2 lastMovePosition;
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
private Bindable<bool> cursorRotate = null!;
|
||||||
private void load([NotNull] OsuConfigManager config, [CanBeNull] ScreenshotManager screenshotManager, AudioManager audio)
|
private Sample tapSample = null!;
|
||||||
|
|
||||||
|
private MouseInputDetector mouseInputDetector = null!;
|
||||||
|
|
||||||
|
private bool visible;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuConfigManager config, ScreenshotManager? screenshotManager, AudioManager audio)
|
||||||
{
|
{
|
||||||
cursorRotate = config.GetBindable<bool>(OsuSetting.CursorRotation);
|
cursorRotate = config.GetBindable<bool>(OsuSetting.CursorRotation);
|
||||||
|
|
||||||
@ -46,6 +47,45 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
screenshotCursorVisibility.BindTo(screenshotManager.CursorVisibility);
|
screenshotCursorVisibility.BindTo(screenshotManager.CursorVisibility);
|
||||||
|
|
||||||
tapSample = audio.Samples.Get(@"UI/cursor-tap");
|
tapSample = audio.Samples.Get(@"UI/cursor-tap");
|
||||||
|
|
||||||
|
Add(mouseInputDetector = new MouseInputDetector());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private OsuGame? game { get; set; }
|
||||||
|
|
||||||
|
private readonly IBindable<bool> lastInputWasMouse = new BindableBool();
|
||||||
|
private readonly IBindable<bool> isIdle = new BindableBool();
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
lastInputWasMouse.BindTo(mouseInputDetector.LastInputWasMouseSource);
|
||||||
|
lastInputWasMouse.BindValueChanged(_ => updateState(), true);
|
||||||
|
|
||||||
|
if (game != null)
|
||||||
|
{
|
||||||
|
isIdle.BindTo(game.IsIdle);
|
||||||
|
isIdle.BindValueChanged(_ => updateState());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void UpdateState(ValueChangedEvent<Visibility> state) => updateState();
|
||||||
|
|
||||||
|
private void updateState()
|
||||||
|
{
|
||||||
|
bool combinedVisibility = State.Value == Visibility.Visible && lastInputWasMouse.Value && !isIdle.Value;
|
||||||
|
|
||||||
|
if (visible == combinedVisibility)
|
||||||
|
return;
|
||||||
|
|
||||||
|
visible = combinedVisibility;
|
||||||
|
|
||||||
|
if (visible)
|
||||||
|
PopIn();
|
||||||
|
else
|
||||||
|
PopOut();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
@ -163,11 +203,11 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
|
|
||||||
public class Cursor : Container
|
public class Cursor : Container
|
||||||
{
|
{
|
||||||
private Container cursorContainer;
|
private Container cursorContainer = null!;
|
||||||
private Bindable<float> cursorScale;
|
private Bindable<float> cursorScale = null!;
|
||||||
private const float base_scale = 0.15f;
|
private const float base_scale = 0.15f;
|
||||||
|
|
||||||
public Sprite AdditiveLayer;
|
public Sprite AdditiveLayer = null!;
|
||||||
|
|
||||||
public Cursor()
|
public Cursor()
|
||||||
{
|
{
|
||||||
@ -204,6 +244,35 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class MouseInputDetector : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the last input applied to the game is sourced from mouse.
|
||||||
|
/// </summary>
|
||||||
|
public IBindable<bool> LastInputWasMouseSource => lastInputWasMouseSource;
|
||||||
|
|
||||||
|
private readonly Bindable<bool> lastInputWasMouseSource = new Bindable<bool>();
|
||||||
|
|
||||||
|
public MouseInputDetector()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool Handle(UIEvent e)
|
||||||
|
{
|
||||||
|
switch (e)
|
||||||
|
{
|
||||||
|
case MouseEvent:
|
||||||
|
lastInputWasMouseSource.Value = true;
|
||||||
|
return false;
|
||||||
|
|
||||||
|
default:
|
||||||
|
lastInputWasMouseSource.Value = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private enum DragRotationState
|
private enum DragRotationState
|
||||||
{
|
{
|
||||||
NotDragging,
|
NotDragging,
|
@ -10,7 +10,6 @@ using osu.Framework.Graphics.Sprites;
|
|||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Game.Localisation;
|
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Overlays.OSD;
|
using osu.Game.Overlays.OSD;
|
||||||
@ -94,15 +93,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
private void copyUrl()
|
private void copyUrl()
|
||||||
{
|
{
|
||||||
host.GetClipboard()?.SetText(Link);
|
host.GetClipboard()?.SetText(Link);
|
||||||
onScreenDisplay?.Display(new CopyUrlToast(ToastStrings.UrlCopied));
|
onScreenDisplay?.Display(new CopyUrlToast());
|
||||||
}
|
|
||||||
|
|
||||||
private class CopyUrlToast : Toast
|
|
||||||
{
|
|
||||||
public CopyUrlToast(LocalisableString value)
|
|
||||||
: base(UserInterfaceStrings.GeneralHeader, value, "")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,6 +70,7 @@ namespace osu.Game
|
|||||||
/// The full osu! experience. Builds on top of <see cref="OsuGameBase"/> to add menus and binding logic
|
/// The full osu! experience. Builds on top of <see cref="OsuGameBase"/> to add menus and binding logic
|
||||||
/// for initial components that are generally retrieved via DI.
|
/// for initial components that are generally retrieved via DI.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Cached(typeof(OsuGame))]
|
||||||
public class OsuGame : OsuGameBase, IKeyBindingHandler<GlobalAction>, ILocalUserPlayInfo, IPerformFromScreenRunner, IOverlayManager, ILinkHandler
|
public class OsuGame : OsuGameBase, IKeyBindingHandler<GlobalAction>, ILocalUserPlayInfo, IPerformFromScreenRunner, IOverlayManager, ILinkHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -136,6 +137,11 @@ namespace osu.Game
|
|||||||
|
|
||||||
private IdleTracker idleTracker;
|
private IdleTracker idleTracker;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the user is currently in an idle state.
|
||||||
|
/// </summary>
|
||||||
|
public IBindable<bool> IsIdle => idleTracker.IsIdle;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether overlays should be able to be opened game-wide. Value is sourced from the current active screen.
|
/// Whether overlays should be able to be opened game-wide. Value is sourced from the current active screen.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -266,8 +272,6 @@ namespace osu.Game
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
dependencies.CacheAs(this);
|
|
||||||
|
|
||||||
SentryLogger.AttachUser(API.LocalUser);
|
SentryLogger.AttachUser(API.LocalUser);
|
||||||
|
|
||||||
dependencies.Cache(osuLogo = new OsuLogo { Alpha = 0 });
|
dependencies.Cache(osuLogo = new OsuLogo { Alpha = 0 });
|
||||||
|
@ -62,6 +62,7 @@ namespace osu.Game
|
|||||||
/// Unlike <see cref="OsuGame"/>, this class will not load any kind of UI, allowing it to be used
|
/// Unlike <see cref="OsuGame"/>, this class will not load any kind of UI, allowing it to be used
|
||||||
/// for provide dependencies to test cases without interfering with them.
|
/// for provide dependencies to test cases without interfering with them.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Cached(typeof(OsuGameBase))]
|
||||||
public partial class OsuGameBase : Framework.Game, ICanAcceptFiles, IBeatSyncProvider
|
public partial class OsuGameBase : Framework.Game, ICanAcceptFiles, IBeatSyncProvider
|
||||||
{
|
{
|
||||||
public static readonly string[] VIDEO_EXTENSIONS = { ".mp4", ".mov", ".avi", ".flv" };
|
public static readonly string[] VIDEO_EXTENSIONS = { ".mp4", ".mov", ".avi", ".flv" };
|
||||||
@ -253,7 +254,6 @@ namespace osu.Game
|
|||||||
largeStore.AddTextureSource(Host.CreateTextureLoaderStore(new OnlineStore()));
|
largeStore.AddTextureSource(Host.CreateTextureLoaderStore(new OnlineStore()));
|
||||||
dependencies.Cache(largeStore);
|
dependencies.Cache(largeStore);
|
||||||
|
|
||||||
dependencies.CacheAs(this);
|
|
||||||
dependencies.CacheAs(LocalConfig);
|
dependencies.CacheAs(LocalConfig);
|
||||||
|
|
||||||
InitialiseFonts();
|
InitialiseFonts();
|
||||||
|
@ -20,11 +20,13 @@ using osu.Framework.Graphics.Shapes;
|
|||||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
|
using osu.Framework.Platform;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.API.Requests;
|
using osu.Game.Online.API.Requests;
|
||||||
using osu.Game.Overlays.Comments.Buttons;
|
using osu.Game.Overlays.Comments.Buttons;
|
||||||
using osu.Game.Overlays.Dialog;
|
using osu.Game.Overlays.Dialog;
|
||||||
|
using osu.Game.Overlays.OSD;
|
||||||
using osu.Game.Resources.Localisation.Web;
|
using osu.Game.Resources.Localisation.Web;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Comments
|
namespace osu.Game.Overlays.Comments
|
||||||
@ -71,6 +73,12 @@ namespace osu.Game.Overlays.Comments
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private IAPIProvider api { get; set; } = null!;
|
private IAPIProvider api { get; set; } = null!;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private GameHost host { get; set; } = null!;
|
||||||
|
|
||||||
|
[Resolved(canBeNull: true)]
|
||||||
|
private OnScreenDisplay? onScreenDisplay { get; set; }
|
||||||
|
|
||||||
public DrawableComment(Comment comment)
|
public DrawableComment(Comment comment)
|
||||||
{
|
{
|
||||||
Comment = comment;
|
Comment = comment;
|
||||||
@ -203,7 +211,6 @@ namespace osu.Game.Overlays.Comments
|
|||||||
{
|
{
|
||||||
Name = @"Actions buttons",
|
Name = @"Actions buttons",
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Spacing = new Vector2(10, 0)
|
|
||||||
},
|
},
|
||||||
actionsLoading = new LoadingSpinner
|
actionsLoading = new LoadingSpinner
|
||||||
{
|
{
|
||||||
@ -323,6 +330,9 @@ namespace osu.Game.Overlays.Comments
|
|||||||
if (WasDeleted)
|
if (WasDeleted)
|
||||||
makeDeleted();
|
makeDeleted();
|
||||||
|
|
||||||
|
actionsContainer.AddLink("Copy link", copyUrl);
|
||||||
|
actionsContainer.AddArbitraryDrawable(new Container { Width = 10 });
|
||||||
|
|
||||||
if (Comment.UserId.HasValue && Comment.UserId.Value == api.LocalUser.Value.Id)
|
if (Comment.UserId.HasValue && Comment.UserId.Value == api.LocalUser.Value.Id)
|
||||||
{
|
{
|
||||||
actionsContainer.AddLink("Delete", deleteComment);
|
actionsContainer.AddLink("Delete", deleteComment);
|
||||||
@ -403,6 +413,12 @@ namespace osu.Game.Overlays.Comments
|
|||||||
api.Queue(request);
|
api.Queue(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void copyUrl()
|
||||||
|
{
|
||||||
|
host.GetClipboard()?.SetText($@"{api.APIEndpointUrl}/comments/{Comment.Id}");
|
||||||
|
onScreenDisplay?.Display(new CopyUrlToast());
|
||||||
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
ShowDeleted.BindValueChanged(show =>
|
ShowDeleted.BindValueChanged(show =>
|
||||||
|
15
osu.Game/Overlays/OSD/CopyUrlToast.cs
Normal file
15
osu.Game/Overlays/OSD/CopyUrlToast.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// 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.Game.Localisation;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.OSD
|
||||||
|
{
|
||||||
|
public class CopyUrlToast : Toast
|
||||||
|
{
|
||||||
|
public CopyUrlToast()
|
||||||
|
: base(UserInterfaceStrings.GeneralHeader, ToastStrings.UrlCopied, "")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -327,6 +327,50 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
finalise();
|
finalise();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override bool OnTabletAuxiliaryButtonPress(TabletAuxiliaryButtonPressEvent e)
|
||||||
|
{
|
||||||
|
if (!HasFocus)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState));
|
||||||
|
finalise();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnTabletAuxiliaryButtonRelease(TabletAuxiliaryButtonReleaseEvent e)
|
||||||
|
{
|
||||||
|
if (!HasFocus)
|
||||||
|
{
|
||||||
|
base.OnTabletAuxiliaryButtonRelease(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
finalise();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnTabletPenButtonPress(TabletPenButtonPressEvent e)
|
||||||
|
{
|
||||||
|
if (!HasFocus)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState));
|
||||||
|
finalise();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnTabletPenButtonRelease(TabletPenButtonReleaseEvent e)
|
||||||
|
{
|
||||||
|
if (!HasFocus)
|
||||||
|
{
|
||||||
|
base.OnTabletPenButtonRelease(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
finalise();
|
||||||
|
}
|
||||||
|
|
||||||
private void clear()
|
private void clear()
|
||||||
{
|
{
|
||||||
if (bindTarget == null)
|
if (bindTarget == null)
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
// 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.
|
||||||
|
|
||||||
#nullable disable
|
using osu.Framework.Allocation;
|
||||||
|
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Caching;
|
using osu.Framework.Caching;
|
||||||
using osu.Framework.Extensions.EnumExtensions;
|
using osu.Framework.Extensions.EnumExtensions;
|
||||||
@ -23,25 +22,38 @@ namespace osu.Game.Overlays
|
|||||||
{
|
{
|
||||||
public class SettingsToolboxGroup : Container, IExpandable
|
public class SettingsToolboxGroup : Container, IExpandable
|
||||||
{
|
{
|
||||||
|
private readonly string title;
|
||||||
public const int CONTAINER_WIDTH = 270;
|
public const int CONTAINER_WIDTH = 270;
|
||||||
|
|
||||||
private const float transition_duration = 250;
|
private const float transition_duration = 250;
|
||||||
private const int border_thickness = 2;
|
|
||||||
private const int header_height = 30;
|
private const int header_height = 30;
|
||||||
private const int corner_radius = 5;
|
private const int corner_radius = 5;
|
||||||
|
|
||||||
private const float fade_duration = 800;
|
|
||||||
private const float inactive_alpha = 0.5f;
|
|
||||||
|
|
||||||
private readonly Cached headerTextVisibilityCache = new Cached();
|
private readonly Cached headerTextVisibilityCache = new Cached();
|
||||||
|
|
||||||
private readonly FillFlowContainer content;
|
protected override Container<Drawable> Content => content;
|
||||||
|
|
||||||
|
private readonly FillFlowContainer content = new FillFlowContainer
|
||||||
|
{
|
||||||
|
Name = @"Content",
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Padding = new MarginPadding { Horizontal = 10, Top = 5, Bottom = 10 },
|
||||||
|
Spacing = new Vector2(0, 15),
|
||||||
|
};
|
||||||
|
|
||||||
public BindableBool Expanded { get; } = new BindableBool(true);
|
public BindableBool Expanded { get; } = new BindableBool(true);
|
||||||
|
|
||||||
private readonly OsuSpriteText headerText;
|
private OsuSpriteText headerText = null!;
|
||||||
|
|
||||||
private readonly Container headerContent;
|
private Container headerContent = null!;
|
||||||
|
|
||||||
|
private Box background = null!;
|
||||||
|
|
||||||
|
private IconButton expandButton = null!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new instance.
|
/// Create a new instance.
|
||||||
@ -49,20 +61,25 @@ namespace osu.Game.Overlays
|
|||||||
/// <param name="title">The title to be displayed in the header of this group.</param>
|
/// <param name="title">The title to be displayed in the header of this group.</param>
|
||||||
public SettingsToolboxGroup(string title)
|
public SettingsToolboxGroup(string title)
|
||||||
{
|
{
|
||||||
|
this.title = title;
|
||||||
|
|
||||||
AutoSizeAxes = Axes.Y;
|
AutoSizeAxes = Axes.Y;
|
||||||
Width = CONTAINER_WIDTH;
|
Width = CONTAINER_WIDTH;
|
||||||
Masking = true;
|
Masking = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader(true)]
|
||||||
|
private void load(OverlayColourProvider? colourProvider)
|
||||||
|
{
|
||||||
CornerRadius = corner_radius;
|
CornerRadius = corner_radius;
|
||||||
BorderColour = Color4.Black;
|
|
||||||
BorderThickness = border_thickness;
|
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
background = new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.Black,
|
Alpha = 0.1f,
|
||||||
Alpha = 0.5f,
|
Colour = colourProvider?.Background4 ?? Color4.Black,
|
||||||
},
|
},
|
||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
@ -88,7 +105,7 @@ namespace osu.Game.Overlays
|
|||||||
Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 17),
|
Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 17),
|
||||||
Padding = new MarginPadding { Left = 10, Right = 30 },
|
Padding = new MarginPadding { Left = 10, Right = 30 },
|
||||||
},
|
},
|
||||||
new IconButton
|
expandButton = new IconButton
|
||||||
{
|
{
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Anchor = Anchor.CentreRight,
|
Anchor = Anchor.CentreRight,
|
||||||
@ -99,19 +116,7 @@ namespace osu.Game.Overlays
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
content = new FillFlowContainer
|
content
|
||||||
{
|
|
||||||
Name = @"Content",
|
|
||||||
Origin = Anchor.TopCentre,
|
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Direction = FillDirection.Vertical,
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
AutoSizeDuration = transition_duration,
|
|
||||||
AutoSizeEasing = Easing.OutQuint,
|
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
Padding = new MarginPadding(15),
|
|
||||||
Spacing = new Vector2(0, 15),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -175,9 +180,10 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
private void updateFadeState()
|
private void updateFadeState()
|
||||||
{
|
{
|
||||||
this.FadeTo(IsHovered ? 1 : inactive_alpha, fade_duration, Easing.OutQuint);
|
const float fade_duration = 500;
|
||||||
}
|
|
||||||
|
|
||||||
protected override Container<Drawable> Content => content;
|
background.FadeTo(IsHovered ? 1 : 0.1f, fade_duration, Easing.OutQuint);
|
||||||
|
expandButton.FadeTo(IsHovered ? 1 : 0, fade_duration, Easing.OutQuint);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,8 @@ using osu.Framework.Bindables;
|
|||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Framework.Extensions.LocalisationExtensions;
|
using osu.Framework.Extensions.LocalisationExtensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
@ -52,20 +54,32 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load(OverlayColourProvider colourProvider)
|
||||||
{
|
{
|
||||||
AddInternal(RightSideToolboxContainer = new ExpandingToolboxContainer(130, 250)
|
AddInternal(new Container
|
||||||
{
|
{
|
||||||
Padding = new MarginPadding(10),
|
|
||||||
Alpha = DistanceSpacingMultiplier.Disabled ? 0 : 1,
|
|
||||||
Anchor = Anchor.TopRight,
|
Anchor = Anchor.TopRight,
|
||||||
Origin = Anchor.TopRight,
|
Origin = Anchor.TopRight,
|
||||||
Child = new EditorToolboxGroup("snapping")
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
AutoSizeAxes = Axes.X,
|
||||||
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
Child = distanceSpacingSlider = new ExpandableSlider<double, SizeSlider<double>>
|
new Box
|
||||||
{
|
{
|
||||||
Current = { BindTarget = DistanceSpacingMultiplier },
|
Colour = colourProvider.Background5,
|
||||||
KeyboardStep = adjust_step,
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
},
|
||||||
|
RightSideToolboxContainer = new ExpandingToolboxContainer(130, 250)
|
||||||
|
{
|
||||||
|
Alpha = DistanceSpacingMultiplier.Disabled ? 0 : 1,
|
||||||
|
Child = new EditorToolboxGroup("snapping")
|
||||||
|
{
|
||||||
|
Child = distanceSpacingSlider = new ExpandableSlider<double, SizeSlider<double>>
|
||||||
|
{
|
||||||
|
Current = { BindTarget = DistanceSpacingMultiplier },
|
||||||
|
KeyboardStep = adjust_step,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -91,7 +105,7 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
|
public virtual bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
|
||||||
{
|
{
|
||||||
switch (e.Action)
|
switch (e.Action)
|
||||||
{
|
{
|
||||||
@ -103,7 +117,7 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnReleased(KeyBindingReleaseEvent<GlobalAction> e)
|
public virtual void OnReleased(KeyBindingReleaseEvent<GlobalAction> e)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,8 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Y;
|
RelativeSizeAxes = Axes.Y;
|
||||||
|
|
||||||
FillFlow.Spacing = new Vector2(10);
|
FillFlow.Spacing = new Vector2(5);
|
||||||
|
Padding = new MarginPadding { Vertical = 5 };
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool ReceivePositionalInputAtSubTree(Vector2 screenSpacePos) => base.ReceivePositionalInputAtSubTree(screenSpacePos) && anyToolboxHovered(screenSpacePos);
|
protected override bool ReceivePositionalInputAtSubTree(Vector2 screenSpacePos) => base.ReceivePositionalInputAtSubTree(screenSpacePos) && anyToolboxHovered(screenSpacePos);
|
||||||
|
@ -12,10 +12,12 @@ using osu.Framework.Bindables;
|
|||||||
using osu.Framework.Extensions.EnumExtensions;
|
using osu.Framework.Extensions.EnumExtensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Rulesets.Configuration;
|
using osu.Game.Rulesets.Configuration;
|
||||||
using osu.Game.Rulesets.Edit.Tools;
|
using osu.Game.Rulesets.Edit.Tools;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
@ -80,7 +82,7 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load(OverlayColourProvider colourProvider)
|
||||||
{
|
{
|
||||||
Config = Dependencies.Get<IRulesetConfigCache>().GetConfigFor(Ruleset);
|
Config = Dependencies.Get<IRulesetConfigCache>().GetConfigFor(Ruleset);
|
||||||
|
|
||||||
@ -102,7 +104,7 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
new Container
|
PlayfieldContentContainer = new Container
|
||||||
{
|
{
|
||||||
Name = "Content",
|
Name = "Content",
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
@ -116,25 +118,37 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
.WithChild(BlueprintContainer = CreateBlueprintContainer())
|
.WithChild(BlueprintContainer = CreateBlueprintContainer())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new ExpandingToolboxContainer(90, 200)
|
new Container
|
||||||
{
|
{
|
||||||
Padding = new MarginPadding(10),
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
AutoSizeAxes = Axes.X,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new EditorToolboxGroup("toolbox (1-9)")
|
new Box
|
||||||
{
|
{
|
||||||
Child = toolboxCollection = new EditorRadioButtonCollection { RelativeSizeAxes = Axes.X }
|
Colour = colourProvider.Background5,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
},
|
},
|
||||||
new EditorToolboxGroup("toggles (Q~P)")
|
new ExpandingToolboxContainer(60, 200)
|
||||||
{
|
{
|
||||||
Child = togglesCollection = new FillFlowContainer
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
new EditorToolboxGroup("toolbox (1-9)")
|
||||||
AutoSizeAxes = Axes.Y,
|
{
|
||||||
Direction = FillDirection.Vertical,
|
Child = toolboxCollection = new EditorRadioButtonCollection { RelativeSizeAxes = Axes.X }
|
||||||
Spacing = new Vector2(0, 5),
|
},
|
||||||
},
|
new EditorToolboxGroup("toggles (Q~P)")
|
||||||
}
|
{
|
||||||
|
Child = togglesCollection = new FillFlowContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Spacing = new Vector2(0, 5),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -152,6 +166,15 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
EditorBeatmap.SelectedHitObjects.CollectionChanged += selectionChanged;
|
EditorBeatmap.SelectedHitObjects.CollectionChanged += selectionChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Houses all content relevant to the playfield.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Generally implementations should not be adding to this directly.
|
||||||
|
/// Use <see cref="LayerBelowRuleset"/> or <see cref="BlueprintContainer"/> instead.
|
||||||
|
/// </remarks>
|
||||||
|
protected Container PlayfieldContentContainer { get; private set; }
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
@ -384,7 +384,7 @@ namespace osu.Game.Rulesets.UI
|
|||||||
// only show the cursor when within the playfield, by default.
|
// only show the cursor when within the playfield, by default.
|
||||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Playfield.ReceivePositionalInputAt(screenSpacePos);
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Playfield.ReceivePositionalInputAt(screenSpacePos);
|
||||||
|
|
||||||
CursorContainer IProvideCursor.MenuCursor => Playfield.Cursor;
|
CursorContainer IProvideCursor.Cursor => Playfield.Cursor;
|
||||||
|
|
||||||
public override GameplayCursorContainer Cursor => Playfield.Cursor;
|
public override GameplayCursorContainer Cursor => Playfield.Cursor;
|
||||||
|
|
||||||
@ -499,6 +499,7 @@ namespace osu.Game.Rulesets.UI
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The cursor being displayed by the <see cref="Playfield"/>. May be null if no cursor is provided.
|
/// The cursor being displayed by the <see cref="Playfield"/>. May be null if no cursor is provided.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[CanBeNull]
|
||||||
public abstract GameplayCursorContainer Cursor { get; }
|
public abstract GameplayCursorContainer Cursor { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -202,16 +202,14 @@ namespace osu.Game.Rulesets.UI
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The cursor currently being used by this <see cref="Playfield"/>. May be null if no cursor is provided.
|
/// The cursor currently being used by this <see cref="Playfield"/>. May be null if no cursor is provided.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[CanBeNull]
|
||||||
public GameplayCursorContainer Cursor { get; private set; }
|
public GameplayCursorContainer Cursor { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provide a cursor which is to be used for gameplay.
|
/// Provide a cursor which is to be used for gameplay.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
|
||||||
/// The default provided cursor is invisible when inside the bounds of the <see cref="Playfield"/>.
|
|
||||||
/// </remarks>
|
|
||||||
/// <returns>The cursor, or null to show the menu cursor.</returns>
|
/// <returns>The cursor, or null to show the menu cursor.</returns>
|
||||||
protected virtual GameplayCursorContainer CreateCursor() => new InvisibleCursorContainer();
|
protected virtual GameplayCursorContainer CreateCursor() => null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Registers a <see cref="Playfield"/> as a nested <see cref="Playfield"/>.
|
/// Registers a <see cref="Playfield"/> as a nested <see cref="Playfield"/>.
|
||||||
@ -522,14 +520,5 @@ namespace osu.Game.Rulesets.UI
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public class InvisibleCursorContainer : GameplayCursorContainer
|
|
||||||
{
|
|
||||||
protected override Drawable CreateCursor() => new InvisibleCursor();
|
|
||||||
|
|
||||||
private class InvisibleCursor : Drawable
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,13 +8,12 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Cursor;
|
using osu.Framework.Graphics.Cursor;
|
||||||
using osu.Framework.Graphics.Effects;
|
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Overlays;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
@ -30,9 +29,9 @@ namespace osu.Game.Screens.Edit.Components.RadioButtons
|
|||||||
public readonly RadioButton Button;
|
public readonly RadioButton Button;
|
||||||
|
|
||||||
private Color4 defaultBackgroundColour;
|
private Color4 defaultBackgroundColour;
|
||||||
private Color4 defaultBubbleColour;
|
private Color4 defaultIconColour;
|
||||||
private Color4 selectedBackgroundColour;
|
private Color4 selectedBackgroundColour;
|
||||||
private Color4 selectedBubbleColour;
|
private Color4 selectedIconColour;
|
||||||
|
|
||||||
private Drawable icon;
|
private Drawable icon;
|
||||||
|
|
||||||
@ -50,20 +49,13 @@ namespace osu.Game.Screens.Edit.Components.RadioButtons
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(OverlayColourProvider colourProvider)
|
||||||
{
|
{
|
||||||
defaultBackgroundColour = colours.Gray3;
|
defaultBackgroundColour = colourProvider.Background3;
|
||||||
defaultBubbleColour = defaultBackgroundColour.Darken(0.5f);
|
selectedBackgroundColour = colourProvider.Background1;
|
||||||
selectedBackgroundColour = colours.BlueDark;
|
|
||||||
selectedBubbleColour = selectedBackgroundColour.Lighten(0.5f);
|
|
||||||
|
|
||||||
Content.EdgeEffect = new EdgeEffectParameters
|
defaultIconColour = defaultBackgroundColour.Darken(0.5f);
|
||||||
{
|
selectedIconColour = selectedBackgroundColour.Lighten(0.5f);
|
||||||
Type = EdgeEffectType.Shadow,
|
|
||||||
Radius = 2,
|
|
||||||
Offset = new Vector2(0, 1),
|
|
||||||
Colour = Color4.Black.Opacity(0.5f)
|
|
||||||
};
|
|
||||||
|
|
||||||
Add(icon = (Button.CreateIcon?.Invoke() ?? new Circle()).With(b =>
|
Add(icon = (Button.CreateIcon?.Invoke() ?? new Circle()).With(b =>
|
||||||
{
|
{
|
||||||
@ -98,7 +90,7 @@ namespace osu.Game.Screens.Edit.Components.RadioButtons
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
BackgroundColour = Button.Selected.Value ? selectedBackgroundColour : defaultBackgroundColour;
|
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
|
protected override SpriteText CreateText() => new OsuSpriteText
|
||||||
|
@ -6,12 +6,11 @@
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Effects;
|
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Overlays;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
@ -20,9 +19,9 @@ namespace osu.Game.Screens.Edit.Components.TernaryButtons
|
|||||||
internal class DrawableTernaryButton : OsuButton
|
internal class DrawableTernaryButton : OsuButton
|
||||||
{
|
{
|
||||||
private Color4 defaultBackgroundColour;
|
private Color4 defaultBackgroundColour;
|
||||||
private Color4 defaultBubbleColour;
|
private Color4 defaultIconColour;
|
||||||
private Color4 selectedBackgroundColour;
|
private Color4 selectedBackgroundColour;
|
||||||
private Color4 selectedBubbleColour;
|
private Color4 selectedIconColour;
|
||||||
|
|
||||||
private Drawable icon;
|
private Drawable icon;
|
||||||
|
|
||||||
@ -38,20 +37,13 @@ namespace osu.Game.Screens.Edit.Components.TernaryButtons
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(OverlayColourProvider colourProvider)
|
||||||
{
|
{
|
||||||
defaultBackgroundColour = colours.Gray3;
|
defaultBackgroundColour = colourProvider.Background3;
|
||||||
defaultBubbleColour = defaultBackgroundColour.Darken(0.5f);
|
selectedBackgroundColour = colourProvider.Background1;
|
||||||
selectedBackgroundColour = colours.BlueDark;
|
|
||||||
selectedBubbleColour = selectedBackgroundColour.Lighten(0.5f);
|
|
||||||
|
|
||||||
Content.EdgeEffect = new EdgeEffectParameters
|
defaultIconColour = defaultBackgroundColour.Darken(0.5f);
|
||||||
{
|
selectedIconColour = selectedBackgroundColour.Lighten(0.5f);
|
||||||
Type = EdgeEffectType.Shadow,
|
|
||||||
Radius = 2,
|
|
||||||
Offset = new Vector2(0, 1),
|
|
||||||
Colour = Color4.Black.Opacity(0.5f)
|
|
||||||
};
|
|
||||||
|
|
||||||
Add(icon = (Button.CreateIcon?.Invoke() ?? new Circle()).With(b =>
|
Add(icon = (Button.CreateIcon?.Invoke() ?? new Circle()).With(b =>
|
||||||
{
|
{
|
||||||
@ -85,17 +77,17 @@ namespace osu.Game.Screens.Edit.Components.TernaryButtons
|
|||||||
switch (Button.Bindable.Value)
|
switch (Button.Bindable.Value)
|
||||||
{
|
{
|
||||||
case TernaryState.Indeterminate:
|
case TernaryState.Indeterminate:
|
||||||
icon.Colour = selectedBubbleColour.Darken(0.5f);
|
icon.Colour = selectedIconColour.Darken(0.5f);
|
||||||
BackgroundColour = selectedBackgroundColour.Darken(0.5f);
|
BackgroundColour = selectedBackgroundColour.Darken(0.5f);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TernaryState.False:
|
case TernaryState.False:
|
||||||
icon.Colour = defaultBubbleColour;
|
icon.Colour = defaultIconColour;
|
||||||
BackgroundColour = defaultBackgroundColour;
|
BackgroundColour = defaultBackgroundColour;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TernaryState.True:
|
case TernaryState.True:
|
||||||
icon.Colour = selectedBubbleColour;
|
icon.Colour = selectedIconColour;
|
||||||
BackgroundColour = selectedBackgroundColour;
|
BackgroundColour = selectedBackgroundColour;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -106,7 +106,6 @@ namespace osu.Game.Screens.Edit
|
|||||||
Name = "Main content",
|
Name = "Main content",
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Depth = float.MaxValue,
|
Depth = float.MaxValue,
|
||||||
Padding = new MarginPadding(10),
|
|
||||||
Child = spinner = new LoadingSpinner(true)
|
Child = spinner = new LoadingSpinner(true)
|
||||||
{
|
{
|
||||||
State = { Value = Visibility.Visible },
|
State = { Value = Visibility.Visible },
|
||||||
|
@ -15,6 +15,7 @@ using osu.Framework.Graphics.Shapes;
|
|||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Scoring;
|
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);
|
public Bindable<LabelStyles> LabelStyle { get; } = new Bindable<LabelStyles>(LabelStyles.Icons);
|
||||||
|
|
||||||
private SpriteIcon arrow;
|
private SpriteIcon arrow;
|
||||||
private Drawable labelEarly;
|
private UprightAspectMaintainingContainer labelEarly;
|
||||||
private Drawable labelLate;
|
private UprightAspectMaintainingContainer labelLate;
|
||||||
|
|
||||||
private Container colourBarsEarly;
|
private Container colourBarsEarly;
|
||||||
private Container colourBarsLate;
|
private Container colourBarsLate;
|
||||||
@ -122,6 +123,20 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
|
|||||||
RelativeSizeAxes = Axes.Y,
|
RelativeSizeAxes = Axes.Y,
|
||||||
Width = judgement_line_width,
|
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
|
arrowContainer = new Container
|
||||||
@ -261,57 +276,39 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
|
|||||||
{
|
{
|
||||||
const float icon_size = 14;
|
const float icon_size = 14;
|
||||||
|
|
||||||
labelEarly?.Expire();
|
|
||||||
labelEarly = null;
|
|
||||||
|
|
||||||
labelLate?.Expire();
|
|
||||||
labelLate = null;
|
|
||||||
|
|
||||||
switch (style)
|
switch (style)
|
||||||
{
|
{
|
||||||
case LabelStyles.None:
|
case LabelStyles.None:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LabelStyles.Icons:
|
case LabelStyles.Icons:
|
||||||
labelEarly = new SpriteIcon
|
labelEarly.Child = new SpriteIcon
|
||||||
{
|
{
|
||||||
Y = -10,
|
|
||||||
Size = new Vector2(icon_size),
|
Size = new Vector2(icon_size),
|
||||||
Icon = FontAwesome.Solid.ShippingFast,
|
Icon = FontAwesome.Solid.ShippingFast,
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
labelLate = new SpriteIcon
|
labelLate.Child = new SpriteIcon
|
||||||
{
|
{
|
||||||
Y = 10,
|
|
||||||
Size = new Vector2(icon_size),
|
Size = new Vector2(icon_size),
|
||||||
Icon = FontAwesome.Solid.Bicycle,
|
Icon = FontAwesome.Solid.Bicycle,
|
||||||
Anchor = Anchor.BottomCentre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LabelStyles.Text:
|
case LabelStyles.Text:
|
||||||
labelEarly = new OsuSpriteText
|
labelEarly.Child = new OsuSpriteText
|
||||||
{
|
{
|
||||||
Y = -10,
|
|
||||||
Text = "Early",
|
Text = "Early",
|
||||||
Font = OsuFont.Default.With(size: 10),
|
Font = OsuFont.Default.With(size: 10),
|
||||||
Height = 12,
|
Height = 12,
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
labelLate = new OsuSpriteText
|
labelLate.Child = new OsuSpriteText
|
||||||
{
|
{
|
||||||
Y = 10,
|
|
||||||
Text = "Late",
|
Text = "Late",
|
||||||
Font = OsuFont.Default.With(size: 10),
|
Font = OsuFont.Default.With(size: 10),
|
||||||
Height = 12,
|
Height = 12,
|
||||||
Anchor = Anchor.BottomCentre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -320,26 +317,8 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
|
|||||||
throw new ArgumentOutOfRangeException(nameof(style), style, null);
|
throw new ArgumentOutOfRangeException(nameof(style), style, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (labelEarly != null)
|
labelEarly.FadeInFromZero(500);
|
||||||
{
|
labelLate.FadeInFromZero(500);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createColourBars((HitResult result, double length)[] windows)
|
private void createColourBars((HitResult result, double length)[] windows)
|
||||||
|
@ -64,6 +64,8 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
protected Task? DisposalTask { get; private set; }
|
protected Task? DisposalTask { get; private set; }
|
||||||
|
|
||||||
|
private OsuScrollContainer settingsScroll = null!;
|
||||||
|
|
||||||
private bool backgroundBrightnessReduction;
|
private bool backgroundBrightnessReduction;
|
||||||
|
|
||||||
private readonly BindableDouble volumeAdjustment = new BindableDouble(1);
|
private readonly BindableDouble volumeAdjustment = new BindableDouble(1);
|
||||||
@ -71,6 +73,9 @@ namespace osu.Game.Screens.Play
|
|||||||
private AudioFilter lowPassFilter = null!;
|
private AudioFilter lowPassFilter = null!;
|
||||||
private AudioFilter highPassFilter = null!;
|
private AudioFilter highPassFilter = null!;
|
||||||
|
|
||||||
|
[Cached]
|
||||||
|
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple);
|
||||||
|
|
||||||
protected bool BackgroundBrightnessReduction
|
protected bool BackgroundBrightnessReduction
|
||||||
{
|
{
|
||||||
set
|
set
|
||||||
@ -165,30 +170,30 @@ namespace osu.Game.Screens.Play
|
|||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = 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),
|
lowPassFilter = new AudioFilter(audio.TrackMixer),
|
||||||
highPassFilter = new AudioFilter(audio.TrackMixer, BQFType.HighPass)
|
highPassFilter = new AudioFilter(audio.TrackMixer, BQFType.HighPass)
|
||||||
};
|
};
|
||||||
@ -224,6 +229,9 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
Beatmap.Value.Track.AddAdjustment(AdjustableProperty.Volume, volumeAdjustment);
|
Beatmap.Value.Track.AddAdjustment(AdjustableProperty.Volume, volumeAdjustment);
|
||||||
|
|
||||||
|
// Start off-screen.
|
||||||
|
settingsScroll.MoveToX(settingsScroll.DrawWidth);
|
||||||
|
|
||||||
content.ScaleTo(0.7f);
|
content.ScaleTo(0.7f);
|
||||||
|
|
||||||
contentIn();
|
contentIn();
|
||||||
@ -313,6 +321,16 @@ namespace osu.Game.Screens.Play
|
|||||||
content.StopTracking();
|
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
|
#endregion
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
@ -391,6 +409,10 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
content.FadeInFromZero(400);
|
content.FadeInFromZero(400);
|
||||||
content.ScaleTo(1, 650, Easing.OutQuint).Then().Schedule(prepareNewPlayer);
|
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);
|
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)
|
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.ScaleTo(0.7f, CONTENT_OUT_DURATION * 2, Easing.OutQuint);
|
||||||
content.FadeOut(CONTENT_OUT_DURATION, 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);
|
lowPassFilter.CutoffTo(AudioFilter.MAX_LOWPASS_CUTOFF, CONTENT_OUT_DURATION);
|
||||||
highPassFilter.CutoffTo(0, CONTENT_OUT_DURATION);
|
highPassFilter.CutoffTo(0, CONTENT_OUT_DURATION);
|
||||||
}
|
}
|
||||||
@ -432,7 +458,7 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
ContentOut();
|
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)
|
// 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).
|
// 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;
|
const double epilepsy_display_length = 3000;
|
||||||
|
|
||||||
pushSequence
|
pushSequence
|
||||||
|
.Delay(CONTENT_OUT_DURATION)
|
||||||
.Schedule(() => epilepsyWarning.State.Value = Visibility.Visible)
|
.Schedule(() => epilepsyWarning.State.Value = Visibility.Visible)
|
||||||
.TransformBindableTo(volumeAdjustment, 0.25, EpilepsyWarning.FADE_DURATION, Easing.OutQuint)
|
.TransformBindableTo(volumeAdjustment, 0.25, EpilepsyWarning.FADE_DURATION, Easing.OutQuint)
|
||||||
.Delay(epilepsy_display_length)
|
.Delay(epilepsy_display_length)
|
||||||
|
@ -86,16 +86,13 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
// Generally a timeout would not happen here as APIAccess will timeout first.
|
// Generally a timeout would not happen here as APIAccess will timeout first.
|
||||||
if (!tcs.Task.Wait(60000))
|
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;
|
return true;
|
||||||
|
|
||||||
void handleTokenFailure(Exception exception)
|
void handleTokenFailure(Exception exception)
|
||||||
{
|
{
|
||||||
// This method may be invoked multiple times due to the Task.Wait call above.
|
tcs.SetResult(false);
|
||||||
// We only really care about the first error.
|
|
||||||
if (!tcs.TrySetResult(false))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (HandleTokenRetrievalFailure(exception))
|
if (HandleTokenRetrievalFailure(exception))
|
||||||
{
|
{
|
||||||
|
@ -36,7 +36,7 @@ namespace osu.Game.Screens.Utility
|
|||||||
|
|
||||||
public readonly Bindable<LatencyVisualMode> VisualMode = new Bindable<LatencyVisualMode>();
|
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;
|
public bool ProvidingUserCursor => IsActiveArea.Value;
|
||||||
|
|
||||||
@ -91,7 +91,7 @@ namespace osu.Game.Screens.Utility
|
|||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
},
|
},
|
||||||
MenuCursor = new LatencyCursorContainer
|
Cursor = new LatencyCursorContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
},
|
},
|
||||||
@ -105,7 +105,7 @@ namespace osu.Game.Screens.Utility
|
|||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
},
|
},
|
||||||
MenuCursor = new LatencyCursorContainer
|
Cursor = new LatencyCursorContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
},
|
},
|
||||||
@ -119,7 +119,7 @@ namespace osu.Game.Screens.Utility
|
|||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
},
|
},
|
||||||
MenuCursor = new LatencyCursorContainer
|
Cursor = new LatencyCursorContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
},
|
},
|
||||||
|
@ -17,6 +17,7 @@ using osu.Framework.Testing;
|
|||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
|
using osu.Game.Graphics.Cursor;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
@ -42,6 +43,8 @@ namespace osu.Game.Tests.Visual
|
|||||||
|
|
||||||
protected override bool CreateNestedActionContainer => false;
|
protected override bool CreateNestedActionContainer => false;
|
||||||
|
|
||||||
|
protected override bool DisplayCursorForManualInput => false;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
@ -119,6 +122,8 @@ namespace osu.Game.Tests.Visual
|
|||||||
|
|
||||||
public RealmAccess Realm => Dependencies.Get<RealmAccess>();
|
public RealmAccess Realm => Dependencies.Get<RealmAccess>();
|
||||||
|
|
||||||
|
public new GlobalCursorDisplay GlobalCursorDisplay => base.GlobalCursorDisplay;
|
||||||
|
|
||||||
public new BackButton BackButton => base.BackButton;
|
public new BackButton BackButton => base.BackButton;
|
||||||
|
|
||||||
public new BeatmapManager BeatmapManager => base.BeatmapManager;
|
public new BeatmapManager BeatmapManager => base.BeatmapManager;
|
||||||
|
@ -36,21 +36,31 @@ namespace osu.Game.Tests.Visual
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual bool CreateNestedActionContainer => true;
|
protected virtual bool CreateNestedActionContainer => true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether a menu cursor controlled by the manual input manager should be displayed.
|
||||||
|
/// True by default, but is disabled for <see cref="OsuGameTestScene"/>s as they provide their own global cursor.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual bool DisplayCursorForManualInput => true;
|
||||||
|
|
||||||
protected OsuManualInputManagerTestScene()
|
protected OsuManualInputManagerTestScene()
|
||||||
{
|
{
|
||||||
GlobalCursorDisplay cursorDisplay;
|
var mainContent = content = new Container { RelativeSizeAxes = Axes.Both };
|
||||||
|
|
||||||
CompositeDrawable mainContent = cursorDisplay = new GlobalCursorDisplay { RelativeSizeAxes = Axes.Both };
|
if (DisplayCursorForManualInput)
|
||||||
|
|
||||||
cursorDisplay.Child = content = new OsuTooltipContainer(cursorDisplay.MenuCursor)
|
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both
|
var cursorDisplay = new GlobalCursorDisplay { RelativeSizeAxes = Axes.Both };
|
||||||
};
|
|
||||||
|
cursorDisplay.Add(new OsuTooltipContainer(cursorDisplay.MenuCursor)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Child = mainContent
|
||||||
|
});
|
||||||
|
|
||||||
|
mainContent = cursorDisplay;
|
||||||
|
}
|
||||||
|
|
||||||
if (CreateNestedActionContainer)
|
if (CreateNestedActionContainer)
|
||||||
{
|
|
||||||
mainContent = new GlobalActionContainer(null).WithChild(mainContent);
|
mainContent = new GlobalActionContainer(null).WithChild(mainContent);
|
||||||
}
|
|
||||||
|
|
||||||
base.Content.AddRange(new Drawable[]
|
base.Content.AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user