// Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; using System.Globalization; using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Bindings; using osu.Framework.MathUtils; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Input.Bindings; using OpenTK; using OpenTK.Graphics; namespace osu.Game.Overlays.Volume { public class VolumeMeter : Container, IKeyBindingHandler { private CircularProgress volumeCircle; public BindableDouble Bindable { get; } = new BindableDouble { MinValue = 0, MaxValue = 1 }; private readonly float circleSize; private readonly Color4 meterColour; private readonly string name; private OsuSpriteText text; private BufferedContainer maxGlow; public VolumeMeter(string name, float circleSize, Color4 meterColour) { this.circleSize = circleSize; this.meterColour = meterColour; this.name = name; AutoSizeAxes = Axes.Both; } [BackgroundDependencyLoader] private void load(OsuColour colours) { Add(new Container { Size = new Vector2(120, 20), CornerRadius = 10, Masking = true, Margin = new MarginPadding { Left = circleSize + 10 }, Origin = Anchor.CentreLeft, Anchor = Anchor.CentreLeft, Children = new Drawable[] { new Box { RelativeSizeAxes = Axes.Both, Colour = colours.Gray1, Alpha = 0.9f, }, new OsuSpriteText { Anchor = Anchor.Centre, Origin = Anchor.Centre, Font = "Exo2.0-Bold", Text = name } } }); CircularProgress bgProgress; Add(new CircularContainer { Masking = true, Size = new Vector2(circleSize), Children = new Drawable[] { new Box { RelativeSizeAxes = Axes.Both, Colour = colours.Gray1, Alpha = 0.9f, }, bgProgress = new CircularProgress { RelativeSizeAxes = Axes.Both, InnerRadius = 0.05f, Rotation = 180, Anchor = Anchor.Centre, Origin = Anchor.Centre, Colour = colours.Gray2, Size = new Vector2(0.8f) }, new Container { Anchor = Anchor.Centre, Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, Size = new Vector2(0.8f), Padding = new MarginPadding(-Blur.KernelSize(5)), Rotation = 180, Child = (volumeCircle = new CircularProgress { RelativeSizeAxes = Axes.Both, InnerRadius = 0.05f, }).WithEffect(new GlowEffect { Colour = meterColour, Strength = 2, PadExtent = true }), }, maxGlow = (text = new OsuSpriteText { Anchor = Anchor.Centre, Origin = Anchor.Centre, Font = "Venera", TextSize = 0.16f * circleSize }).WithEffect(new GlowEffect { Colour = Color4.Transparent, PadExtent = true, }) } }); Bindable.ValueChanged += newVolume => { this.TransformTo("DisplayVolume", newVolume, 400, Easing.OutQuint); }; bgProgress.Current.Value = 0.75f; } protected override void LoadComplete() { base.LoadComplete(); Bindable.TriggerChange(); } private double displayVolume; protected double DisplayVolume { get => displayVolume; set { displayVolume = value; if (displayVolume > 0.99f) { text.Text = "MAX"; maxGlow.EffectColour = meterColour.Opacity(2f); } else { maxGlow.EffectColour = Color4.Transparent; text.Text = Math.Round(displayVolume * 100).ToString(CultureInfo.CurrentCulture); } volumeCircle.Current.Value = displayVolume * 0.75f; } } public double Volume { get => Bindable; private set => Bindable.Value = value; } private const float adjust_step = 0.05f; public void Increase() => adjust(1); public void Decrease() => adjust(-1); private void adjust(int direction) { float amount = adjust_step * direction; var mouse = GetContainingInputManager().CurrentState.Mouse; if (mouse.HasPreciseScroll) { float scrollDelta = mouse.ScrollDelta.Y; if (scrollDelta != 0) amount *= Math.Abs(scrollDelta / 10); } Volume += amount; } public bool OnPressed(GlobalAction action) { if (!IsHovered) return false; switch (action) { case GlobalAction.DecreaseVolume: Decrease(); return true; case GlobalAction.IncreaseVolume: Increase(); return true; } return false; } public bool OnReleased(GlobalAction action) => false; } }