MouseHeldDown.cs 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. #nullable enable
  2. using System.ComponentModel;
  3. namespace Terminal.Gui.ViewBase;
  4. /// <summary>
  5. /// INTERNAL: Manages the logic for handling a "mouse held down" state on a View. It is used to
  6. /// repeatedly trigger an action (via events) while the mouse button is held down, such as for auto-repeat in
  7. /// scrollbars or buttons.
  8. /// </summary>
  9. internal class MouseHeldDown : IMouseHeldDown
  10. {
  11. public MouseHeldDown (View host, ITimedEvents? timedEvents, IMouseGrabHandler? mouseGrabber)
  12. {
  13. _mouseGrabView = host;
  14. _timedEvents = timedEvents;
  15. _mouseGrabber = mouseGrabber;
  16. _smoothTimeout = new (TimeSpan.FromMilliseconds (500), TimeSpan.FromMilliseconds (50), 0.5, TickWhileMouseIsHeldDown);
  17. }
  18. private readonly View _mouseGrabView;
  19. private readonly ITimedEvents? _timedEvents;
  20. private readonly IMouseGrabHandler? _mouseGrabber;
  21. private readonly SmoothAcceleratingTimeout _smoothTimeout;
  22. private bool _isDown;
  23. private object? _timeout;
  24. public event EventHandler<CancelEventArgs>? MouseIsHeldDownTick;
  25. public void Start ()
  26. {
  27. if (_isDown)
  28. {
  29. return;
  30. }
  31. _isDown = true;
  32. _mouseGrabber?.GrabMouse (_mouseGrabView);
  33. // Then periodic ticks
  34. _timeout = _timedEvents?.Add (_smoothTimeout);
  35. }
  36. public void Stop ()
  37. {
  38. _smoothTimeout.Reset ();
  39. if (_mouseGrabber?.MouseGrabView == _mouseGrabView)
  40. {
  41. _mouseGrabber?.UngrabMouse ();
  42. }
  43. if (_timeout != null)
  44. {
  45. _timedEvents?.Remove (_timeout);
  46. }
  47. _mouseGrabView.MouseState = MouseState.None;
  48. _isDown = false;
  49. }
  50. public void Dispose ()
  51. {
  52. if (_mouseGrabber?.MouseGrabView == _mouseGrabView)
  53. {
  54. Stop ();
  55. }
  56. }
  57. protected virtual bool OnMouseIsHeldDownTick (CancelEventArgs eventArgs) { return false; }
  58. private bool RaiseMouseIsHeldDownTick ()
  59. {
  60. CancelEventArgs args = new ();
  61. args.Cancel = OnMouseIsHeldDownTick (args) || args.Cancel;
  62. if (!args.Cancel && MouseIsHeldDownTick is { })
  63. {
  64. MouseIsHeldDownTick?.Invoke (this, args);
  65. }
  66. // User event cancelled the mouse held down status so
  67. // stop the currently running operation.
  68. if (args.Cancel)
  69. {
  70. Stop ();
  71. }
  72. return args.Cancel;
  73. }
  74. private bool TickWhileMouseIsHeldDown ()
  75. {
  76. Logging.Debug ("Raising TickWhileMouseIsHeldDown...");
  77. if (_isDown)
  78. {
  79. _smoothTimeout.AdvanceStage ();
  80. RaiseMouseIsHeldDownTick ();
  81. }
  82. else
  83. {
  84. _smoothTimeout.Reset ();
  85. Stop ();
  86. }
  87. return _isDown;
  88. }
  89. }