#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)) }; } }