1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 19:22:54 +08:00
osu-lazer/osu.Game/Screens/Edit/Timing/RepeatingButtonBehaviour.cs
2022-06-17 16:37:17 +09:00

100 lines
2.9 KiB
C#

// 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.
#nullable disable
using System;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Graphics;
using osu.Framework.Input.Events;
using osu.Framework.Threading;
namespace osu.Game.Screens.Edit.Timing
{
/// <summary>
/// Represents a component that provides the behaviour of triggering button clicks repeatedly while holding with mouse.
/// </summary>
public class RepeatingButtonBehaviour : Component
{
private const double initial_delay = 300;
private const double minimum_delay = 80;
private readonly Drawable button;
private Sample sample;
public Action RepeatBegan;
public Action RepeatEnded;
/// <summary>
/// An additive modifier for the frequency of the sample played on next actuation.
/// This can be adjusted during the button's <see cref="Drawable.OnClick"/> event to affect the repeat sample playback of that click.
/// </summary>
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)
{
RepeatBegan?.Invoke();
beginRepeat();
return true;
}
protected override void OnMouseUp(MouseUpEvent e)
{
adjustDelegate?.Cancel();
RepeatEnded?.Invoke();
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);
}
}
}
}