#nullable enable
namespace Terminal.Gui;
///
/// Not to be confused with
///
internal class MouseButtonStateEx
{
private readonly Func _now;
private readonly TimeSpan _repeatClickThreshold;
private readonly int _buttonIdx;
private int _consecutiveClicks;
private Point _lastPosition;
///
/// When the button entered its current state.
///
public DateTime At { get; set; }
///
/// if the button is currently down
///
public bool Pressed { get; set; }
public MouseButtonStateEx (Func now, TimeSpan repeatClickThreshold, int buttonIdx)
{
_now = now;
_repeatClickThreshold = repeatClickThreshold;
_buttonIdx = buttonIdx;
}
public void UpdateState (MouseEventArgs e, out int? numClicks)
{
bool isPressedNow = IsPressed (_buttonIdx, e.Flags);
bool isSamePosition = _lastPosition == e.Position;
TimeSpan elapsed = _now () - At;
if (elapsed > _repeatClickThreshold || !isSamePosition)
{
// Expired
OverwriteState (e);
_consecutiveClicks = 0;
numClicks = null;
}
else
{
if (isPressedNow == Pressed)
{
// No change in button state so do nothing
numClicks = null;
return;
}
if (Pressed)
{
// Click released
numClicks = ++_consecutiveClicks;
}
else
{
numClicks = null;
}
// Record new state
OverwriteState (e);
}
}
private void OverwriteState (MouseEventArgs e)
{
Pressed = IsPressed (_buttonIdx, e.Flags);
At = _now ();
_lastPosition = e.Position;
}
private bool IsPressed (int btn, MouseFlags eFlags)
{
return btn switch
{
0 => eFlags.HasFlag (MouseFlags.Button1Pressed),
1 => eFlags.HasFlag (MouseFlags.Button2Pressed),
2 => eFlags.HasFlag (MouseFlags.Button3Pressed),
3 => eFlags.HasFlag (MouseFlags.Button4Pressed),
_ => throw new ArgumentOutOfRangeException (nameof (btn))
};
}
}