2024-01-26 09:49:23 +08:00
|
|
|
// 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.
|
|
|
|
|
|
|
|
using System;
|
2024-01-29 01:01:37 +08:00
|
|
|
using osu.Framework.Allocation;
|
2024-01-28 23:06:09 +08:00
|
|
|
using osu.Framework.Graphics.Containers;
|
|
|
|
using osu.Framework.Input.Events;
|
2024-01-26 09:49:23 +08:00
|
|
|
using osu.Framework.Threading;
|
2024-01-28 23:06:09 +08:00
|
|
|
using osuTK;
|
2024-01-26 09:49:23 +08:00
|
|
|
|
|
|
|
namespace osu.Game.Screens.Play.HUD
|
|
|
|
{
|
2024-01-29 00:49:34 +08:00
|
|
|
public abstract partial class SongProgressBar : CompositeDrawable
|
2024-01-26 09:49:23 +08:00
|
|
|
{
|
2024-01-29 01:01:37 +08:00
|
|
|
/// <summary>
|
|
|
|
/// The current seek position of the audio, on a (0..1) range.
|
|
|
|
/// This is generally the seek target, which will eventually match the gameplay clock when it catches up.
|
|
|
|
/// </summary>
|
|
|
|
protected double AudioProgress => length == 0 ? 1 : AudioTime / length;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// The current (non-frame-stable) audio time.
|
|
|
|
/// </summary>
|
|
|
|
protected double AudioTime => Math.Clamp(GameplayClock.CurrentTime - StartTime, 0.0, length);
|
|
|
|
|
|
|
|
[Resolved]
|
|
|
|
protected IGameplayClock GameplayClock { get; private set; } = null!;
|
|
|
|
|
2024-01-26 09:49:23 +08:00
|
|
|
/// <summary>
|
|
|
|
/// Action which is invoked when a seek is requested, with the proposed millisecond value for the seek operation.
|
|
|
|
/// </summary>
|
|
|
|
public Action<double>? OnSeek { get; set; }
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Whether the progress bar should allow interaction, ie. to perform seek operations.
|
|
|
|
/// </summary>
|
2024-01-29 01:13:39 +08:00
|
|
|
public virtual bool Interactive { get; set; }
|
2024-01-26 09:49:23 +08:00
|
|
|
|
2024-01-28 23:06:09 +08:00
|
|
|
public double StartTime { get; set; }
|
|
|
|
|
|
|
|
public double EndTime { get; set; } = 1.0;
|
|
|
|
|
|
|
|
private double length => EndTime - StartTime;
|
|
|
|
|
|
|
|
private bool handleClick;
|
|
|
|
|
|
|
|
protected override bool OnMouseDown(MouseDownEvent e)
|
2024-01-26 09:49:23 +08:00
|
|
|
{
|
2024-01-28 23:06:09 +08:00
|
|
|
handleClick = true;
|
|
|
|
return base.OnMouseDown(e);
|
2024-01-26 09:49:23 +08:00
|
|
|
}
|
|
|
|
|
2024-01-28 23:06:09 +08:00
|
|
|
protected override bool OnClick(ClickEvent e)
|
2024-01-26 09:49:23 +08:00
|
|
|
{
|
2024-01-28 23:06:09 +08:00
|
|
|
if (handleClick)
|
|
|
|
handleMouseInput(e);
|
|
|
|
|
|
|
|
return true;
|
2024-01-26 09:49:23 +08:00
|
|
|
}
|
|
|
|
|
2024-01-28 23:06:09 +08:00
|
|
|
protected override void OnDrag(DragEvent e)
|
2024-01-26 09:49:23 +08:00
|
|
|
{
|
2024-01-28 23:06:09 +08:00
|
|
|
handleMouseInput(e);
|
2024-01-26 09:49:23 +08:00
|
|
|
}
|
|
|
|
|
2024-01-28 23:06:09 +08:00
|
|
|
protected override bool OnDragStart(DragStartEvent e)
|
2024-01-26 09:49:23 +08:00
|
|
|
{
|
2024-01-28 23:06:09 +08:00
|
|
|
Vector2 posDiff = e.MouseDownPosition - e.MousePosition;
|
|
|
|
|
|
|
|
if (Math.Abs(posDiff.X) < Math.Abs(posDiff.Y))
|
|
|
|
{
|
|
|
|
handleClick = false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
handleMouseInput(e);
|
|
|
|
return true;
|
2024-01-26 09:49:23 +08:00
|
|
|
}
|
|
|
|
|
2024-01-28 23:06:09 +08:00
|
|
|
private void handleMouseInput(UIEvent e)
|
2024-01-26 09:49:23 +08:00
|
|
|
{
|
2024-01-28 23:06:09 +08:00
|
|
|
if (!Interactive)
|
|
|
|
return;
|
|
|
|
|
|
|
|
double relativeX = Math.Clamp(ToLocalSpace(e.ScreenSpaceMousePosition).X / DrawWidth, 0, 1);
|
|
|
|
onUserChange(StartTime + (EndTime - StartTime) * relativeX);
|
2024-01-26 09:49:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
private ScheduledDelegate? scheduledSeek;
|
|
|
|
|
2024-01-28 23:06:09 +08:00
|
|
|
private void onUserChange(double value)
|
2024-01-26 09:49:23 +08:00
|
|
|
{
|
|
|
|
scheduledSeek?.Cancel();
|
2024-01-28 23:06:09 +08:00
|
|
|
scheduledSeek = Schedule(() => OnSeek?.Invoke(value));
|
2024-01-26 09:49:23 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|