using System.ComponentModel;
namespace Terminal.Gui.ViewBase;
///
/// INTERNAL: Manages the logic for handling a "mouse held down" state on a View. It is used to
/// repeatedly trigger an action (via events) while the mouse button is held down, such as for auto-repeat in
/// scrollbars or buttons.
///
internal class MouseHeldDown : IMouseHeldDown
{
public MouseHeldDown (View host, ITimedEvents? timedEvents, IMouseGrabHandler? mouseGrabber)
{
_mouseGrabView = host;
_timedEvents = timedEvents;
_mouseGrabber = mouseGrabber;
_smoothTimeout = new (TimeSpan.FromMilliseconds (500), TimeSpan.FromMilliseconds (50), 0.5, TickWhileMouseIsHeldDown);
}
private readonly View _mouseGrabView;
private readonly ITimedEvents? _timedEvents;
private readonly IMouseGrabHandler? _mouseGrabber;
private readonly SmoothAcceleratingTimeout _smoothTimeout;
private bool _isDown;
private object? _timeout;
public event EventHandler? MouseIsHeldDownTick;
public void Start ()
{
if (_isDown)
{
return;
}
_isDown = true;
_mouseGrabber?.GrabMouse (_mouseGrabView);
// Then periodic ticks
_timeout = _timedEvents?.Add (_smoothTimeout);
}
public void Stop ()
{
_smoothTimeout.Reset ();
if (_mouseGrabber?.MouseGrabView == _mouseGrabView)
{
_mouseGrabber?.UngrabMouse ();
}
if (_timeout != null)
{
_timedEvents?.Remove (_timeout);
}
_mouseGrabView.MouseState = MouseState.None;
_isDown = false;
}
public void Dispose ()
{
if (_mouseGrabber?.MouseGrabView == _mouseGrabView)
{
Stop ();
}
}
protected virtual bool OnMouseIsHeldDownTick (CancelEventArgs eventArgs) { return false; }
private bool RaiseMouseIsHeldDownTick ()
{
CancelEventArgs args = new ();
args.Cancel = OnMouseIsHeldDownTick (args) || args.Cancel;
if (!args.Cancel && MouseIsHeldDownTick is { })
{
MouseIsHeldDownTick?.Invoke (this, args);
}
// User event cancelled the mouse held down status so
// stop the currently running operation.
if (args.Cancel)
{
Stop ();
}
return args.Cancel;
}
private bool TickWhileMouseIsHeldDown ()
{
Logging.Debug ("Raising TickWhileMouseIsHeldDown...");
if (_isDown)
{
_smoothTimeout.AdvanceStage ();
RaiseMouseIsHeldDownTick ();
}
else
{
_smoothTimeout.Reset ();
Stop ();
}
return _isDown;
}
}