Implement ability to switch between volume meters

This commit is contained in:
Derrick Timmermans 2021-07-04 14:47:07 +02:00
parent 49090a0d1b
commit d1553f0864
No known key found for this signature in database
GPG Key ID: 8681B60806EF4A17
4 changed files with 91 additions and 15 deletions

View File

@ -103,6 +103,9 @@ namespace osu.Game.Input.Bindings
new KeyBinding(new[] { InputKey.Alt, InputKey.Up }, GlobalAction.IncreaseVolume), new KeyBinding(new[] { InputKey.Alt, InputKey.Up }, GlobalAction.IncreaseVolume),
new KeyBinding(new[] { InputKey.Alt, InputKey.Down }, GlobalAction.DecreaseVolume), new KeyBinding(new[] { InputKey.Alt, InputKey.Down }, GlobalAction.DecreaseVolume),
new KeyBinding(new[] { InputKey.Alt, InputKey.Left }, GlobalAction.PreviousVolumeMeter),
new KeyBinding(new[] { InputKey.Alt, InputKey.Right }, GlobalAction.NextVolumeMeter),
new KeyBinding(new[] { InputKey.Control, InputKey.F4 }, GlobalAction.ToggleMute), new KeyBinding(new[] { InputKey.Control, InputKey.F4 }, GlobalAction.ToggleMute),
new KeyBinding(InputKey.TrackPrevious, GlobalAction.MusicPrev), new KeyBinding(InputKey.TrackPrevious, GlobalAction.MusicPrev),
@ -263,5 +266,11 @@ namespace osu.Game.Input.Bindings
[Description("Toggle skin editor")] [Description("Toggle skin editor")]
ToggleSkinEditor, ToggleSkinEditor,
[Description("Previous volume meter")]
PreviousVolumeMeter,
[Description("Next volume meter")]
NextVolumeMeter,
} }
} }

View File

@ -30,6 +30,8 @@ namespace osu.Game.Overlays.Volume
return true; return true;
case GlobalAction.ToggleMute: case GlobalAction.ToggleMute:
case GlobalAction.NextVolumeMeter:
case GlobalAction.PreviousVolumeMeter:
ActionRequested?.Invoke(action); ActionRequested?.Invoke(action);
return true; return true;
} }

View File

@ -12,6 +12,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Transforms;
using osu.Framework.Graphics.UserInterface; using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
@ -27,6 +28,11 @@ namespace osu.Game.Overlays.Volume
{ {
public class VolumeMeter : Container, IKeyBindingHandler<GlobalAction> public class VolumeMeter : Container, IKeyBindingHandler<GlobalAction>
{ {
[Resolved(canBeNull: true)]
private Bindable<VolumeMeter> focusedMeter { get; set; }
private bool isFocused => focusedMeter == null || focusedMeter.Value == this;
private CircularProgress volumeCircle; private CircularProgress volumeCircle;
private CircularProgress volumeCircleGlow; private CircularProgress volumeCircleGlow;
@ -41,6 +47,8 @@ namespace osu.Game.Overlays.Volume
private Sample sample; private Sample sample;
private double sampleLastPlaybackTime; private double sampleLastPlaybackTime;
public Action<VolumeMeter> RequestFocus;
public VolumeMeter(string name, float circleSize, Color4 meterColour) public VolumeMeter(string name, float circleSize, Color4 meterColour)
{ {
this.circleSize = circleSize; this.circleSize = circleSize;
@ -310,20 +318,32 @@ namespace osu.Game.Overlays.Volume
private const float transition_length = 500; private const float transition_length = 500;
public void Focus()
{
if (focusedMeter != null)
focusedMeter.Value = this;
this.ScaleTo(1.04f, transition_length, Easing.OutExpo);
}
public void Unfocus()
{
this.ScaleTo(1f, transition_length, Easing.OutExpo);
}
protected override bool OnHover(HoverEvent e) protected override bool OnHover(HoverEvent e)
{ {
this.ScaleTo(1.04f, transition_length, Easing.OutExpo); Focus();
return false; return false;
} }
protected override void OnHoverLost(HoverLostEvent e) protected override void OnHoverLost(HoverLostEvent e)
{ {
this.ScaleTo(1f, transition_length, Easing.OutExpo);
} }
public bool OnPressed(GlobalAction action) public bool OnPressed(GlobalAction action)
{ {
if (!IsHovered) if (!IsHovered || !isFocused)
return false; return false;
switch (action) switch (action)

View File

@ -19,6 +19,7 @@ using osuTK.Graphics;
namespace osu.Game.Overlays namespace osu.Game.Overlays
{ {
[Cached]
public class VolumeOverlay : VisibilityContainer public class VolumeOverlay : VisibilityContainer
{ {
private const float offset = 10; private const float offset = 10;
@ -32,6 +33,8 @@ namespace osu.Game.Overlays
public Bindable<bool> IsMuted { get; } = new Bindable<bool>(); public Bindable<bool> IsMuted { get; } = new Bindable<bool>();
private FillFlowContainer<VolumeMeter> volumeMeters;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(AudioManager audio, OsuColour colours) private void load(AudioManager audio, OsuColour colours)
{ {
@ -53,7 +56,7 @@ namespace osu.Game.Overlays
Margin = new MarginPadding(10), Margin = new MarginPadding(10),
Current = { BindTarget = IsMuted } Current = { BindTarget = IsMuted }
}, },
new FillFlowContainer volumeMeters = new FillFlowContainer<VolumeMeter>
{ {
Direction = FillDirection.Vertical, Direction = FillDirection.Vertical,
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
@ -61,7 +64,7 @@ namespace osu.Game.Overlays
Origin = Anchor.CentreLeft, Origin = Anchor.CentreLeft,
Spacing = new Vector2(0, offset), Spacing = new Vector2(0, offset),
Margin = new MarginPadding { Left = offset }, Margin = new MarginPadding { Left = offset },
Children = new Drawable[] Children = new VolumeMeter[]
{ {
volumeMeterEffect = new VolumeMeter("EFFECTS", 125, colours.BlueDarker), volumeMeterEffect = new VolumeMeter("EFFECTS", 125, colours.BlueDarker),
volumeMeterMaster = new VolumeMeter("MASTER", 150, colours.PinkDarker), volumeMeterMaster = new VolumeMeter("MASTER", 150, colours.PinkDarker),
@ -81,8 +84,13 @@ namespace osu.Game.Overlays
else else
audio.RemoveAdjustment(AdjustableProperty.Volume, muteAdjustment); audio.RemoveAdjustment(AdjustableProperty.Volume, muteAdjustment);
}); });
focusedMeter.BindValueChanged(meter => meter.OldValue?.Unfocus());
} }
[Cached]
private Bindable<VolumeMeter> focusedMeter = new Bindable<VolumeMeter>();
protected override void LoadComplete() protected override void LoadComplete()
{ {
base.LoadComplete(); base.LoadComplete();
@ -93,6 +101,23 @@ namespace osu.Game.Overlays
muteButton.Current.ValueChanged += _ => Show(); muteButton.Current.ValueChanged += _ => Show();
} }
public bool HandleAction(GlobalAction action)
{
if (!IsLoaded) return false;
switch (action)
{
case GlobalAction.DecreaseVolume:
case GlobalAction.IncreaseVolume:
return Adjust(action);
case GlobalAction.NextVolumeMeter:
return true;
}
return true;
}
public bool Adjust(GlobalAction action, float amount = 1, bool isPrecise = false) public bool Adjust(GlobalAction action, float amount = 1, bool isPrecise = false)
{ {
if (!IsLoaded) return false; if (!IsLoaded) return false;
@ -102,25 +127,32 @@ namespace osu.Game.Overlays
case GlobalAction.DecreaseVolume: case GlobalAction.DecreaseVolume:
if (State.Value == Visibility.Hidden) if (State.Value == Visibility.Hidden)
Show(); Show();
else if (volumeMeterMusic.IsHovered)
volumeMeterMusic.Decrease(amount, isPrecise);
else if (volumeMeterEffect.IsHovered)
volumeMeterEffect.Decrease(amount, isPrecise);
else else
volumeMeterMaster.Decrease(amount, isPrecise); focusedMeter.Value.Decrease(amount, isPrecise);
return true; return true;
case GlobalAction.IncreaseVolume: case GlobalAction.IncreaseVolume:
if (State.Value == Visibility.Hidden) if (State.Value == Visibility.Hidden)
Show(); Show();
else if (volumeMeterMusic.IsHovered)
volumeMeterMusic.Increase(amount, isPrecise);
else if (volumeMeterEffect.IsHovered)
volumeMeterEffect.Increase(amount, isPrecise);
else else
volumeMeterMaster.Increase(amount, isPrecise); focusedMeter.Value.Increase(amount, isPrecise);
return true; return true;
case GlobalAction.NextVolumeMeter:
if (State.Value == Visibility.Hidden)
Show();
else
focusShift(1);
return true;
case GlobalAction.PreviousVolumeMeter:
if (State.Value == Visibility.Hidden)
Show();
else
focusShift(-1);
return true;
case GlobalAction.ToggleMute: case GlobalAction.ToggleMute:
Show(); Show();
muteButton.Current.Value = !muteButton.Current.Value; muteButton.Current.Value = !muteButton.Current.Value;
@ -130,10 +162,23 @@ namespace osu.Game.Overlays
return false; return false;
} }
private void focusShift(int direction = 1)
{
Show();
var newIndex = volumeMeters.IndexOf(focusedMeter.Value) + direction;
if (newIndex < 0)
newIndex += volumeMeters.Count;
volumeMeters.Children[newIndex % volumeMeters.Count].Focus();
}
private ScheduledDelegate popOutDelegate; private ScheduledDelegate popOutDelegate;
public override void Show() public override void Show()
{ {
if (State.Value == Visibility.Hidden)
volumeMeterMaster.Focus();
if (State.Value == Visibility.Visible) if (State.Value == Visibility.Visible)
schedulePopOut(); schedulePopOut();