1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 12:33:01 +08:00

Merge pull request #1706 from smoogipoo/play-overlay-selections

Implement keyboard controls in gameplay overlays (pause/fail)
This commit is contained in:
Dean Herbert 2017-12-18 21:43:14 +09:00 committed by GitHub
commit 7c8a33b757
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 541 additions and 259 deletions

View File

@ -0,0 +1,258 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using OpenTK.Input;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
using osu.Framework.Logging;
using osu.Game.Screens.Play;
namespace osu.Game.Tests.Visual
{
[Description("player pause/fail screens")]
internal class TestCaseGameplayMenuOverlay : OsuTestCase
{
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(FailOverlay), typeof(PauseContainer) };
private FailOverlay failOverlay;
private PauseContainer.PauseOverlay pauseOverlay;
[BackgroundDependencyLoader]
private void load()
{
Add(pauseOverlay = new PauseContainer.PauseOverlay
{
OnResume = () => Logger.Log(@"Resume"),
OnRetry = () => Logger.Log(@"Retry"),
OnQuit = () => Logger.Log(@"Quit"),
});
Add(failOverlay = new FailOverlay
{
OnRetry = () => Logger.Log(@"Retry"),
OnQuit = () => Logger.Log(@"Quit"),
});
var retryCount = 0;
AddStep("Add retry", () =>
{
retryCount++;
pauseOverlay.Retries = failOverlay.Retries = retryCount;
});
AddToggleStep("Toggle pause overlay", t => pauseOverlay.ToggleVisibility());
AddToggleStep("Toggle fail overlay", t => failOverlay.ToggleVisibility());
testHideResets();
testEnterWithoutSelection();
testKeyUpFromInitial();
testKeyDownFromInitial();
testKeyUpWrapping();
testKeyDownWrapping();
testMouseSelectionAfterKeySelection();
testKeySelectionAfterMouseSelection();
testMouseDeselectionResets();
testClickSelection();
testEnterKeySelection();
}
/// <summary>
/// Test that hiding the overlay after hovering a button will reset the overlay to the initial state with no buttons selected.
/// </summary>
private void testHideResets()
{
AddStep("Show overlay", () => failOverlay.Show());
AddStep("Hover first button", () => failOverlay.Buttons.First().TriggerOnHover(null));
AddStep("Hide overlay", () => failOverlay.Hide());
AddAssert("Overlay state is reset", () => !failOverlay.Buttons.Any(b => b.Selected));
}
/// <summary>
/// Tests that pressing enter after an overlay shows doesn't trigger an event because a selection hasn't occurred.
/// </summary>
private void testEnterWithoutSelection()
{
AddStep("Show overlay", () => pauseOverlay.Show());
AddStep("Press enter", () => pauseOverlay.TriggerOnKeyDown(null, new KeyDownEventArgs { Key = Key.Enter }));
AddAssert("Overlay still open", () => pauseOverlay.State == Visibility.Visible);
AddStep("Hide overlay", () => pauseOverlay.Hide());
}
/// <summary>
/// Tests that pressing the up arrow from the initial state selects the last button.
/// </summary>
private void testKeyUpFromInitial()
{
AddStep("Show overlay", () => pauseOverlay.Show());
AddStep("Up arrow", () => pauseOverlay.TriggerOnKeyDown(null, new KeyDownEventArgs { Key = Key.Up }));
AddAssert("Last button selected", () => pauseOverlay.Buttons.Last().Selected);
AddStep("Hide overlay", () => pauseOverlay.Hide());
}
/// <summary>
/// Tests that pressing the down arrow from the initial state selects the first button.
/// </summary>
private void testKeyDownFromInitial()
{
AddStep("Show overlay", () => pauseOverlay.Show());
AddStep("Down arrow", () => pauseOverlay.TriggerOnKeyDown(null, new KeyDownEventArgs { Key = Key.Down }));
AddAssert("First button selected", () => pauseOverlay.Buttons.First().Selected);
AddStep("Hide overlay", () => pauseOverlay.Hide());
}
/// <summary>
/// Tests that pressing the up arrow repeatedly causes the selected button to wrap correctly.
/// </summary>
private void testKeyUpWrapping()
{
AddStep("Show overlay", () => failOverlay.Show());
AddStep("Up arrow", () => failOverlay.TriggerOnKeyDown(null, new KeyDownEventArgs { Key = Key.Up }));
AddAssert("Last button selected", () => failOverlay.Buttons.Last().Selected);
AddStep("Up arrow", () => failOverlay.TriggerOnKeyDown(null, new KeyDownEventArgs { Key = Key.Up }));
AddAssert("First button selected", () => failOverlay.Buttons.First().Selected);
AddStep("Up arrow", () => failOverlay.TriggerOnKeyDown(null, new KeyDownEventArgs { Key = Key.Up }));
AddAssert("Last button selected", () => failOverlay.Buttons.Last().Selected);
AddStep("Hide overlay", () => failOverlay.Hide());
}
/// <summary>
/// Tests that pressing the down arrow repeatedly causes the selected button to wrap correctly.
/// </summary>
private void testKeyDownWrapping()
{
AddStep("Show overlay", () => failOverlay.Show());
AddStep("Down arrow", () => failOverlay.TriggerOnKeyDown(null, new KeyDownEventArgs { Key = Key.Down }));
AddAssert("First button selected", () => failOverlay.Buttons.First().Selected);
AddStep("Down arrow", () => failOverlay.TriggerOnKeyDown(null, new KeyDownEventArgs { Key = Key.Down }));
AddAssert("Last button selected", () => failOverlay.Buttons.Last().Selected);
AddStep("Down arrow", () => failOverlay.TriggerOnKeyDown(null, new KeyDownEventArgs { Key = Key.Down }));
AddAssert("First button selected", () => failOverlay.Buttons.First().Selected);
AddStep("Hide overlay", () => failOverlay.Hide());
}
/// <summary>
/// Tests that hovering a button that was previously selected with the keyboard correctly selects the new button and deselects the previous button.
/// </summary>
private void testMouseSelectionAfterKeySelection()
{
AddStep("Show overlay", () => pauseOverlay.Show());
var secondButton = pauseOverlay.Buttons.Skip(1).First();
AddStep("Down arrow", () => pauseOverlay.TriggerOnKeyDown(null, new KeyDownEventArgs { Key = Key.Down }));
AddStep("Hover second button", () => secondButton.TriggerOnHover(null));
AddAssert("First button not selected", () => !pauseOverlay.Buttons.First().Selected);
AddAssert("Second button selected", () => secondButton.Selected);
AddStep("Hide overlay", () => pauseOverlay.Hide());
}
/// <summary>
/// Tests that pressing a key after selecting a button with a hover event correctly selects a new button and deselects the previous button.
/// </summary>
private void testKeySelectionAfterMouseSelection()
{
AddStep("Show overlay", () => pauseOverlay.Show());
var secondButton = pauseOverlay.Buttons.Skip(1).First();
AddStep("Hover second button", () => secondButton.TriggerOnHover(null));
AddStep("Up arrow", () => pauseOverlay.TriggerOnKeyDown(null, new KeyDownEventArgs { Key = Key.Up }));
AddAssert("Second button not selected", () => !secondButton.Selected);
AddAssert("First button selected", () => pauseOverlay.Buttons.First().Selected);
AddStep("Hide overlay", () => pauseOverlay.Hide());
}
/// <summary>
/// Tests that deselecting with the mouse by losing hover will reset the overlay to the initial state.
/// </summary>
private void testMouseDeselectionResets()
{
AddStep("Show overlay", () => pauseOverlay.Show());
var secondButton = pauseOverlay.Buttons.Skip(1).First();
AddStep("Hover second button", () => secondButton.TriggerOnHover(null));
AddStep("Unhover second button", () => secondButton.TriggerOnHoverLost(null));
AddStep("Down arrow", () => pauseOverlay.TriggerOnKeyDown(null, new KeyDownEventArgs { Key = Key.Down }));
AddAssert("First button selected", () => pauseOverlay.Buttons.First().Selected); // Initial state condition
AddStep("Hide overlay", () => pauseOverlay.Hide());
}
/// <summary>
/// Tests that clicking on a button correctly causes a click event for that button.
/// </summary>
private void testClickSelection()
{
AddStep("Show overlay", () => pauseOverlay.Show());
var retryButton = pauseOverlay.Buttons.Skip(1).First();
bool triggered = false;
AddStep("Click retry button", () =>
{
var lastAction = pauseOverlay.OnRetry;
pauseOverlay.OnRetry = () => triggered = true;
retryButton.TriggerOnClick();
pauseOverlay.OnRetry = lastAction;
});
AddAssert("Action was triggered", () => triggered);
AddAssert("Overlay is closed", () => pauseOverlay.State == Visibility.Hidden);
}
/// <summary>
/// Tests that pressing the enter key with a button selected correctly causes a click event for that button.
/// </summary>
private void testEnterKeySelection()
{
AddStep("Show overlay", () => pauseOverlay.Show());
AddStep("Select second button", () =>
{
pauseOverlay.TriggerOnKeyDown(null, new KeyDownEventArgs { Key = Key.Down });
pauseOverlay.TriggerOnKeyDown(null, new KeyDownEventArgs { Key = Key.Down });
});
var retryButton = pauseOverlay.Buttons.Skip(1).First();
bool triggered = false;
AddStep("Press enter", () =>
{
var lastAction = pauseOverlay.OnRetry;
pauseOverlay.OnRetry = () => triggered = true;
retryButton.TriggerOnKeyDown(null, new KeyDownEventArgs { Key = Key.Enter });
pauseOverlay.OnRetry = lastAction;
});
AddAssert("Action was triggered", () => triggered);
AddAssert("Overlay is closed", () => pauseOverlay.State == Visibility.Hidden);
}
}
}

View File

@ -1,57 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.ComponentModel;
using osu.Framework.Graphics.Containers;
using osu.Framework.Logging;
using osu.Game.Screens.Play;
namespace osu.Game.Tests.Visual
{
[Description("player pause/fail screens")]
internal class TestCaseMenuOverlays : OsuTestCase
{
public TestCaseMenuOverlays()
{
FailOverlay failOverlay;
PauseContainer.PauseOverlay pauseOverlay;
var retryCount = 0;
Add(pauseOverlay = new PauseContainer.PauseOverlay
{
OnResume = () => Logger.Log(@"Resume"),
OnRetry = () => Logger.Log(@"Retry"),
OnQuit = () => Logger.Log(@"Quit"),
});
Add(failOverlay = new FailOverlay
{
OnRetry = () => Logger.Log(@"Retry"),
OnQuit = () => Logger.Log(@"Quit"),
});
AddStep(@"Pause", delegate
{
if (failOverlay.State == Visibility.Visible)
{
failOverlay.Hide();
}
pauseOverlay.Show();
});
AddStep("Fail", delegate
{
if (pauseOverlay.State == Visibility.Visible)
{
pauseOverlay.Hide();
}
failOverlay.Show();
});
AddStep("Add Retry", delegate
{
retryCount++;
pauseOverlay.Retries = retryCount;
failOverlay.Retries = retryCount;
});
}
}
}

View File

@ -120,7 +120,7 @@
<Compile Include="Visual\TestCaseLeaderboard.cs" />
<Compile Include="Visual\TestCaseMedalOverlay.cs" />
<Compile Include="Visual\TestCaseButtonSystem.cs" />
<Compile Include="Visual\TestCaseMenuOverlays.cs" />
<Compile Include="Visual\TestCaseGameplayMenuOverlay.cs" />
<Compile Include="Visual\TestCaseMods.cs" />
<Compile Include="Visual\TestCaseMusicController.cs" />
<Compile Include="Visual\TestCaseNotificationOverlay.cs" />

View File

@ -12,6 +12,8 @@ using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Sprites;
using osu.Framework.Extensions.Color4Extensions;
using osu.Game.Graphics.Containers;
using osu.Framework.Configuration;
using osu.Framework.Input;
namespace osu.Game.Graphics.UserInterface
{
@ -22,62 +24,7 @@ namespace osu.Game.Graphics.UserInterface
private const float glow_fade_duration = 250;
private const float click_duration = 200;
private Color4 buttonColour;
public Color4 ButtonColour
{
get
{
return buttonColour;
}
set
{
buttonColour = value;
updateGlow();
colourContainer.Colour = value;
}
}
private Color4 backgroundColour = OsuColour.Gray(34);
public Color4 BackgroundColour
{
get
{
return backgroundColour;
}
set
{
backgroundColour = value;
background.Colour = value;
}
}
private string text;
public string Text
{
get
{
return text;
}
set
{
text = value;
spriteText.Text = Text;
}
}
private float textSize = 28;
public float TextSize
{
get
{
return textSize;
}
set
{
textSize = value;
spriteText.TextSize = value;
}
}
public readonly BindableBool Selected = new BindableBool();
private readonly Container backgroundContainer;
private readonly Container colourContainer;
@ -89,71 +36,6 @@ namespace osu.Game.Graphics.UserInterface
private readonly SpriteText spriteText;
private Vector2 hoverSpacing => new Vector2(3f, 0f);
private bool didClick; // Used for making sure that the OnMouseDown animation can call instead of OnHoverLost's when clicking
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => backgroundContainer.ReceiveMouseInputAt(screenSpacePos);
protected override bool OnClick(Framework.Input.InputState state)
{
didClick = true;
colourContainer.ResizeTo(new Vector2(1.5f, 1f), click_duration, Easing.In);
flash();
this.Delay(click_duration).Schedule(delegate
{
colourContainer.ResizeTo(new Vector2(0.8f, 1f));
spriteText.Spacing = Vector2.Zero;
glowContainer.FadeOut();
});
return base.OnClick(state);
}
protected override bool OnHover(Framework.Input.InputState state)
{
spriteText.TransformSpacingTo(hoverSpacing, hover_duration, Easing.OutElastic);
colourContainer.ResizeTo(new Vector2(hover_width, 1f), hover_duration, Easing.OutElastic);
glowContainer.FadeIn(glow_fade_duration, Easing.Out);
base.OnHover(state);
return true;
}
protected override void OnHoverLost(Framework.Input.InputState state)
{
if (!didClick)
{
colourContainer.ResizeTo(new Vector2(0.8f, 1f), hover_duration, Easing.OutElastic);
spriteText.TransformSpacingTo(Vector2.Zero, hover_duration, Easing.OutElastic);
glowContainer.FadeOut(glow_fade_duration, Easing.Out);
}
didClick = false;
}
private void flash()
{
var flash = new Box
{
RelativeSizeAxes = Axes.Both
};
colourContainer.Add(flash);
flash.Colour = ButtonColour;
flash.Blending = BlendingMode.Additive;
flash.Alpha = 0.3f;
flash.FadeOutFromOne(click_duration);
flash.Expire();
}
private void updateGlow()
{
leftGlow.Colour = ColourInfo.GradientHorizontal(new Color4(ButtonColour.R, ButtonColour.G, ButtonColour.B, 0f), ButtonColour);
centerGlow.Colour = ButtonColour;
rightGlow.Colour = ColourInfo.GradientHorizontal(ButtonColour, new Color4(ButtonColour.R, ButtonColour.G, ButtonColour.B, 0f));
}
public DialogButton()
{
RelativeSizeAxes = Axes.X;
@ -268,6 +150,135 @@ namespace osu.Game.Graphics.UserInterface
};
updateGlow();
Selected.ValueChanged += selectionChanged;
}
private Color4 buttonColour;
public Color4 ButtonColour
{
get
{
return buttonColour;
}
set
{
buttonColour = value;
updateGlow();
colourContainer.Colour = value;
}
}
private Color4 backgroundColour = OsuColour.Gray(34);
public Color4 BackgroundColour
{
get
{
return backgroundColour;
}
set
{
backgroundColour = value;
background.Colour = value;
}
}
private string text;
public string Text
{
get
{
return text;
}
set
{
text = value;
spriteText.Text = Text;
}
}
private float textSize = 28;
public float TextSize
{
get
{
return textSize;
}
set
{
textSize = value;
spriteText.TextSize = value;
}
}
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => backgroundContainer.ReceiveMouseInputAt(screenSpacePos);
protected override bool OnClick(InputState state)
{
colourContainer.ResizeTo(new Vector2(1.5f, 1f), click_duration, Easing.In);
flash();
this.Delay(click_duration).Schedule(delegate
{
colourContainer.ResizeTo(new Vector2(0.8f, 1f));
spriteText.Spacing = Vector2.Zero;
glowContainer.FadeOut();
});
return base.OnClick(state);
}
protected override bool OnHover(InputState state)
{
base.OnHover(state);
Selected.Value = true;
return true;
}
protected override void OnHoverLost(InputState state)
{
base.OnHoverLost(state);
Selected.Value = false;
}
private void selectionChanged(bool isSelected)
{
if (isSelected)
{
spriteText.TransformSpacingTo(hoverSpacing, hover_duration, Easing.OutElastic);
colourContainer.ResizeTo(new Vector2(hover_width, 1f), hover_duration, Easing.OutElastic);
glowContainer.FadeIn(glow_fade_duration, Easing.Out);
}
else
{
colourContainer.ResizeTo(new Vector2(0.8f, 1f), hover_duration, Easing.OutElastic);
spriteText.TransformSpacingTo(Vector2.Zero, hover_duration, Easing.OutElastic);
glowContainer.FadeOut(glow_fade_duration, Easing.Out);
}
}
private void flash()
{
var flash = new Box
{
RelativeSizeAxes = Axes.Both
};
colourContainer.Add(flash);
flash.Colour = ButtonColour;
flash.Blending = BlendingMode.Additive;
flash.Alpha = 0.3f;
flash.FadeOutFromOne(click_duration);
flash.Expire();
}
private void updateGlow()
{
leftGlow.Colour = ColourInfo.GradientHorizontal(new Color4(ButtonColour.R, ButtonColour.G, ButtonColour.B, 0f), ButtonColour);
centerGlow.Colour = ButtonColour;
rightGlow.Colour = ColourInfo.GradientHorizontal(ButtonColour, new Color4(ButtonColour.R, ButtonColour.G, ButtonColour.B, 0f));
}
}
}

View File

@ -10,7 +10,7 @@ using System.Linq;
namespace osu.Game.Screens.Play
{
public class FailOverlay : MenuOverlay
public class FailOverlay : GameplayMenuOverlay
{
public override string Header => "failed";
public override string Description => "you're dead, try again?";
@ -18,15 +18,15 @@ namespace osu.Game.Screens.Play
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
AddButton("Retry", colours.YellowDark, OnRetry);
AddButton("Quit", new Color4(170, 27, 39, 255), OnQuit);
AddButton("Retry", colours.YellowDark, () => OnRetry?.Invoke());
AddButton("Quit", new Color4(170, 27, 39, 255), () => OnQuit?.Invoke());
}
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
if (!args.Repeat && args.Key == Key.Escape)
{
Buttons.Children.Last().TriggerOnClick();
InternalButtons.Children.Last().TriggerOnClick();
return true;
}

View File

@ -13,10 +13,12 @@ using osu.Game.Graphics;
using osu.Framework.Allocation;
using osu.Game.Graphics.UserInterface;
using osu.Framework.Graphics.Shapes;
using OpenTK.Input;
using System.Collections.Generic;
namespace osu.Game.Screens.Play
{
public abstract class MenuOverlay : OverlayContainer, IRequireHighFrequencyMousePosition
public abstract class GameplayMenuOverlay : OverlayContainer, IRequireHighFrequencyMousePosition
{
private const int transition_duration = 200;
private const int button_height = 70;
@ -30,75 +32,16 @@ namespace osu.Game.Screens.Play
public abstract string Header { get; }
public abstract string Description { get; }
protected FillFlowContainer<DialogButton> Buttons;
public int Retries
{
set
{
if (retryCounterContainer != null)
{
// "You've retried 1,065 times in this session"
// "You've retried 1 time in this session"
retryCounterContainer.Children = new Drawable[]
{
new OsuSpriteText
{
Text = "You've retried ",
Shadow = true,
ShadowColour = new Color4(0, 0, 0, 0.25f),
TextSize = 18
},
new OsuSpriteText
{
Text = $"{value:n0}",
Font = @"Exo2.0-Bold",
Shadow = true,
ShadowColour = new Color4(0, 0, 0, 0.25f),
TextSize = 18
},
new OsuSpriteText
{
Text = $" time{(value == 1 ? "" : "s")} in this session",
Shadow = true,
ShadowColour = new Color4(0, 0, 0, 0.25f),
TextSize = 18
}
};
}
}
}
protected internal FillFlowContainer<DialogButton> InternalButtons;
public IReadOnlyList<DialogButton> Buttons => InternalButtons;
private FillFlowContainer retryCounterContainer;
public override bool HandleInput => State == Visibility.Visible;
protected override void PopIn() => this.FadeIn(transition_duration, Easing.In);
protected override void PopOut() => this.FadeOut(transition_duration, Easing.In);
// Don't let mouse down events through the overlay or people can click circles while paused.
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) => true;
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) => true;
protected override bool OnMouseMove(InputState state) => true;
protected void AddButton(string text, Color4 colour, Action action)
protected GameplayMenuOverlay()
{
Buttons.Add(new Button
{
Text = text,
ButtonColour = colour,
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
Height = button_height,
Action = delegate
{
action?.Invoke();
Hide();
}
});
RelativeSizeAxes = Axes.Both;
StateChanged += s => selectionIndex = -1;
}
[BackgroundDependencyLoader]
@ -154,7 +97,7 @@ namespace osu.Game.Screens.Play
}
}
},
Buttons = new FillFlowContainer<DialogButton>
InternalButtons = new FillFlowContainer<DialogButton>
{
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
@ -182,13 +125,140 @@ namespace osu.Game.Screens.Play
Retries = 0;
}
protected MenuOverlay()
public int Retries
{
RelativeSizeAxes = Axes.Both;
set
{
if (retryCounterContainer != null)
{
// "You've retried 1,065 times in this session"
// "You've retried 1 time in this session"
retryCounterContainer.Children = new Drawable[]
{
new OsuSpriteText
{
Text = "You've retried ",
Shadow = true,
ShadowColour = new Color4(0, 0, 0, 0.25f),
TextSize = 18
},
new OsuSpriteText
{
Text = $"{value:n0}",
Font = @"Exo2.0-Bold",
Shadow = true,
ShadowColour = new Color4(0, 0, 0, 0.25f),
TextSize = 18
},
new OsuSpriteText
{
Text = $" time{(value == 1 ? "" : "s")} in this session",
Shadow = true,
ShadowColour = new Color4(0, 0, 0, 0.25f),
TextSize = 18
}
};
}
}
}
public class Button : DialogButton
public override bool HandleInput => State == Visibility.Visible;
protected override void PopIn() => this.FadeIn(transition_duration, Easing.In);
protected override void PopOut() => this.FadeOut(transition_duration, Easing.In);
// Don't let mouse down events through the overlay or people can click circles while paused.
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) => true;
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) => true;
protected override bool OnMouseMove(InputState state) => true;
protected void AddButton(string text, Color4 colour, Action action)
{
var button = new Button
{
Text = text,
ButtonColour = colour,
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
Height = button_height,
Action = delegate
{
action?.Invoke();
Hide();
}
};
button.Selected.ValueChanged += s => buttonSelectionChanged(button, s);
InternalButtons.Add(button);
}
private int _selectionIndex = -1;
private int selectionIndex
{
get { return _selectionIndex; }
set
{
if (_selectionIndex == value)
return;
// Deselect the previously-selected button
if (_selectionIndex != -1)
InternalButtons[_selectionIndex].Selected.Value = false;
_selectionIndex = value;
// Select the newly-selected button
if (_selectionIndex != -1)
InternalButtons[_selectionIndex].Selected.Value = true;
}
}
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
if (args.Repeat)
return false;
switch (args.Key)
{
case Key.Up:
if (selectionIndex == -1 || selectionIndex == 0)
selectionIndex = InternalButtons.Count - 1;
else
selectionIndex--;
return true;
case Key.Down:
if (selectionIndex == -1 || selectionIndex == InternalButtons.Count - 1)
selectionIndex = 0;
else
selectionIndex++;
return true;
}
return false;
}
private void buttonSelectionChanged(DialogButton button, bool isSelected)
{
if (!isSelected)
selectionIndex = -1;
else
selectionIndex = InternalButtons.IndexOf(button);
}
private class Button : DialogButton
{
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
if (args.Repeat || args.Key != Key.Enter || !Selected)
return false;
OnClick(state);
return true;
}
}
}
}

View File

@ -119,7 +119,7 @@ namespace osu.Game.Screens.Play
base.Update();
}
public class PauseOverlay : MenuOverlay
public class PauseOverlay : GameplayMenuOverlay
{
public Action OnResume;
@ -130,7 +130,7 @@ namespace osu.Game.Screens.Play
{
if (!args.Repeat && args.Key == Key.Escape)
{
Buttons.Children.First().TriggerOnClick();
InternalButtons.Children.First().TriggerOnClick();
return true;
}
@ -140,9 +140,9 @@ namespace osu.Game.Screens.Play
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
AddButton("Continue", colours.Green, OnResume);
AddButton("Retry", colours.YellowDark, OnRetry);
AddButton("Quit", new Color4(170, 27, 39, 255), OnQuit);
AddButton("Continue", colours.Green, () => OnResume?.Invoke());
AddButton("Retry", colours.YellowDark, () => OnRetry?.Invoke());
AddButton("Quit", new Color4(170, 27, 39, 255), () => OnQuit?.Invoke());
}
}
}

View File

@ -719,7 +719,7 @@
<Compile Include="Screens\Play\KeyCounterCollection.cs" />
<Compile Include="Screens\Play\KeyCounterKeyboard.cs" />
<Compile Include="Screens\Play\KeyCounterMouse.cs" />
<Compile Include="Screens\Play\MenuOverlay.cs" />
<Compile Include="Screens\Play\GameplayMenuOverlay.cs" />
<Compile Include="Screens\Play\PauseContainer.cs" />
<Compile Include="Screens\Play\Player.cs" />
<Compile Include="Screens\Play\PlayerLoader.cs" />