MouseHeldDown.cs 2.7 KB

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