diff --git a/osu.Game/Screens/Edit/Timing/RepeatingButtonBehaviour.cs b/osu.Game/Screens/Edit/Timing/RepeatingButtonBehaviour.cs new file mode 100644 index 0000000000..5c9f384a2e --- /dev/null +++ b/osu.Game/Screens/Edit/Timing/RepeatingButtonBehaviour.cs @@ -0,0 +1,93 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Input.Events; +using osu.Framework.Threading; + +namespace osu.Game.Screens.Edit.Timing +{ + /// + /// Represents a component that provides the behaviour of triggering button clicks repeatedly while holding with mouse. + /// + public class RepeatingButtonBehaviour : CompositeDrawable + { + private const double initial_delay = 300; + private const double minimum_delay = 80; + + private readonly Drawable button; + + private Sample sample; + + /// + /// An additive modifier for the frequency of the sample played on next actuation. + /// This can be adjusted during the button's event to affect the repeat sample playback of that click. + /// + public double SampleFrequencyModifier { get; set; } + + public RepeatingButtonBehaviour(Drawable button) + { + this.button = button; + + RelativeSizeAxes = Axes.Both; + } + + [BackgroundDependencyLoader] + private void load(AudioManager audio) + { + sample = audio.Samples.Get(@"UI/notch-tick"); + } + + protected override bool OnMouseDown(MouseDownEvent e) + { + beginRepeat(); + return true; + } + + protected override void OnMouseUp(MouseUpEvent e) + { + adjustDelegate?.Cancel(); + base.OnMouseUp(e); + } + + private ScheduledDelegate adjustDelegate; + private double adjustDelay = initial_delay; + + private void beginRepeat() + { + adjustDelegate?.Cancel(); + + adjustDelay = initial_delay; + adjustNext(); + + void adjustNext() + { + if (IsHovered) + { + button.TriggerClick(); + adjustDelay = Math.Max(minimum_delay, adjustDelay * 0.9f); + + var channel = sample?.GetChannel(); + + if (channel != null) + { + double repeatModifier = 0.05f * (Math.Abs(adjustDelay - initial_delay) / minimum_delay); + channel.Frequency.Value = 1 + repeatModifier + SampleFrequencyModifier; + channel.Play(); + } + } + else + { + adjustDelay = initial_delay; + } + + adjustDelegate = Scheduler.AddDelayed(adjustNext, adjustDelay); + } + } + } +} diff --git a/osu.Game/Screens/Edit/Timing/TimingAdjustButton.cs b/osu.Game/Screens/Edit/Timing/TimingAdjustButton.cs index 9fc7e56a3d..6e7338fa15 100644 --- a/osu.Game/Screens/Edit/Timing/TimingAdjustButton.cs +++ b/osu.Game/Screens/Edit/Timing/TimingAdjustButton.cs @@ -4,14 +4,11 @@ using System; using System.Linq; using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Audio.Sample; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; using osu.Framework.Localisation; -using osu.Framework.Threading; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Overlays; @@ -26,32 +23,24 @@ namespace osu.Game.Screens.Edit.Timing public Action Action; private readonly double adjustAmount; - private ScheduledDelegate adjustDelegate; private const int max_multiplier = 10; - private const int adjust_levels = 4; - private const double initial_delay = 300; - - private const double minimum_delay = 80; - public Container Content { get; set; } - private double adjustDelay = initial_delay; - private readonly Box background; private readonly OsuSpriteText text; - private Sample sample; - public LocalisableString Text { get => text.Text; set => text.Text = value; } + private readonly RepeatingButtonBehaviour repeatBehaviour; + [Resolved] private OverlayColourProvider colourProvider { get; set; } @@ -82,13 +71,13 @@ namespace osu.Game.Screens.Edit.Timing } } }); + + AddInternal(repeatBehaviour = new RepeatingButtonBehaviour(this)); } [BackgroundDependencyLoader] - private void load(AudioManager audio) + private void load() { - sample = audio.Samples.Get(@"UI/notch-tick"); - background.Colour = colourProvider.Background3; for (int i = 1; i <= adjust_levels; i++) @@ -98,57 +87,22 @@ namespace osu.Game.Screens.Edit.Timing } } - protected override bool OnMouseDown(MouseDownEvent e) + protected override bool OnHover(HoverEvent e) => true; + + protected override bool OnClick(ClickEvent e) { - beginRepeat(); + var hoveredBox = Content.OfType().FirstOrDefault(d => d.IsHovered); + if (hoveredBox == null) + return false; + + Action(adjustAmount * hoveredBox.Multiplier); + + hoveredBox.Flash(); + + repeatBehaviour.SampleFrequencyModifier = (hoveredBox.Multiplier / max_multiplier) * 0.2; return true; } - protected override void OnMouseUp(MouseUpEvent e) - { - adjustDelegate?.Cancel(); - base.OnMouseUp(e); - } - - private void beginRepeat() - { - adjustDelegate?.Cancel(); - - adjustDelay = initial_delay; - adjustNext(); - - void adjustNext() - { - var hoveredBox = Content.OfType().FirstOrDefault(d => d.IsHovered); - - if (hoveredBox != null) - { - Action(adjustAmount * hoveredBox.Multiplier); - - adjustDelay = Math.Max(minimum_delay, adjustDelay * 0.9f); - - hoveredBox.Flash(); - - var channel = sample?.GetChannel(); - - if (channel != null) - { - double repeatModifier = 0.05f * (Math.Abs(adjustDelay - initial_delay) / minimum_delay); - double multiplierModifier = (hoveredBox.Multiplier / max_multiplier) * 0.2f; - - channel.Frequency.Value = 1 + multiplierModifier + repeatModifier; - channel.Play(); - } - } - else - { - adjustDelay = initial_delay; - } - - adjustDelegate = Scheduler.AddDelayed(adjustNext, adjustDelay); - } - } - private class IncrementBox : CompositeDrawable { public readonly float Multiplier;