diff --git a/Terminal.Gui/Application/Application.cs b/Terminal.Gui/Application/Application.cs
index 947cab271b..47d0090e00 100644
--- a/Terminal.Gui/Application/Application.cs
+++ b/Terminal.Gui/Application/Application.cs
@@ -137,6 +137,9 @@ internal static void ResetState (bool ignoreDisposed = false)
// Mouse
_mouseEnteredView = null;
+ _lastViewButtonPressed = null;
+ _canProcessClickedEvent = true;
+ _isMouseDown = false;
WantContinuousButtonPressedView = null;
MouseEvent = null;
GrabbedMouse = null;
diff --git a/Terminal.Gui/Application/ApplicationMouse.cs b/Terminal.Gui/Application/ApplicationMouse.cs
index 9f2a953390..ee5782f4e4 100644
--- a/Terminal.Gui/Application/ApplicationMouse.cs
+++ b/Terminal.Gui/Application/ApplicationMouse.cs
@@ -114,6 +114,9 @@ private static void OnUnGrabbedMouse (View view)
// Used by OnMouseEvent to track the last view that was clicked on.
internal static View? _mouseEnteredView;
+ internal static View? _lastViewButtonPressed;
+ internal static bool _canProcessClickedEvent = true;
+ internal static bool? _isMouseDown;
/// Event fired when a mouse move or click occurs. Coordinates are screen relative.
///
@@ -142,6 +145,38 @@ internal static void OnMouseEvent (MouseEvent mouseEvent)
mouseEvent.View = view;
}
+ if (_lastViewButtonPressed is null && mouseEvent.Flags is MouseFlags.Button1Pressed or MouseFlags.Button2Pressed or MouseFlags.Button3Pressed or MouseFlags.Button4Pressed)
+ {
+ _lastViewButtonPressed = view;
+ _isMouseDown = true;
+ }
+ else if (_lastViewButtonPressed is { } && mouseEvent.Flags is MouseFlags.Button1Released or MouseFlags.Button2Released or MouseFlags.Button3Released or MouseFlags.Button4Released)
+ {
+ if (_lastViewButtonPressed != view)
+ {
+ _canProcessClickedEvent = false;
+ }
+
+ _lastViewButtonPressed = null;
+ _isMouseDown = false;
+ }
+ else if (!_canProcessClickedEvent && mouseEvent.Flags is MouseFlags.Button1Clicked or MouseFlags.Button2Clicked or MouseFlags.Button3Clicked or MouseFlags.Button4Clicked)
+ {
+ _canProcessClickedEvent = true;
+ _isMouseDown = null;
+
+ return;
+ }
+ else if (!mouseEvent.Flags.HasFlag (MouseFlags.ReportMousePosition))
+ {
+ _lastViewButtonPressed = null;
+ _isMouseDown = null;
+ }
+ else
+ {
+ _isMouseDown = null;
+ }
+
MouseEvent?.Invoke (null, mouseEvent);
if (mouseEvent.Handled)
@@ -160,7 +195,8 @@ internal static void OnMouseEvent (MouseEvent mouseEvent)
Position = frameLoc,
Flags = mouseEvent.Flags,
ScreenPosition = mouseEvent.Position,
- View = MouseGrabView
+ View = MouseGrabView,
+ IsMouseDown = _isMouseDown
};
if ((MouseGrabView.Viewport with { Location = Point.Empty }).Contains (viewRelativeMouseEvent.Position) is false)
@@ -170,7 +206,8 @@ internal static void OnMouseEvent (MouseEvent mouseEvent)
}
//System.Diagnostics.Debug.WriteLine ($"{nme.Flags};{nme.X};{nme.Y};{mouseGrabView}");
- if (MouseGrabView?.NewMouseEvent (viewRelativeMouseEvent) == true)
+ if ((MouseGrabView?.WantMousePositionReports == true || MouseGrabView?.WantContinuousButtonPressed == true)
+ && MouseGrabView?.NewMouseEvent (viewRelativeMouseEvent) == true)
{
return;
}
@@ -221,7 +258,8 @@ internal static void OnMouseEvent (MouseEvent mouseEvent)
Position = frameLoc,
Flags = mouseEvent.Flags,
ScreenPosition = mouseEvent.Position,
- View = view
+ View = view,
+ IsMouseDown = _isMouseDown
};
}
else if (view.ViewportToScreen (Rectangle.Empty with { Size = view.Viewport.Size }).Contains (mouseEvent.Position))
@@ -233,7 +271,8 @@ internal static void OnMouseEvent (MouseEvent mouseEvent)
Position = viewportLocation,
Flags = mouseEvent.Flags,
ScreenPosition = mouseEvent.Position,
- View = view
+ View = view,
+ IsMouseDown = _isMouseDown
};
}
diff --git a/Terminal.Gui/Input/Mouse.cs b/Terminal.Gui/Input/Mouse.cs
index 3c8c98e91f..67a18f3169 100644
--- a/Terminal.Gui/Input/Mouse.cs
+++ b/Terminal.Gui/Input/Mouse.cs
@@ -134,6 +134,11 @@ public class MouseEvent
///
public Point ScreenPosition { get; set; }
+ ///
+ /// Indicates if the current mouse event has first pressed , latest released or none .
+ ///
+ public bool? IsMouseDown { get; set; }
+
///
/// Indicates if the current mouse event has been processed. Set this value to to indicate the mouse
/// event was handled.
diff --git a/Terminal.Gui/View/Adornment/Border.cs b/Terminal.Gui/View/Adornment/Border.cs
index 2931cd9ad2..560cf916d6 100644
--- a/Terminal.Gui/View/Adornment/Border.cs
+++ b/Terminal.Gui/View/Adornment/Border.cs
@@ -59,6 +59,7 @@ public Border (View parent) : base (parent)
HighlightStyle |= HighlightStyle.Pressed;
Highlight += Border_Highlight;
+ WantMousePositionReports = true;
}
#if SUBVIEW_BASED_BORDER
diff --git a/Terminal.Gui/View/ViewMouse.cs b/Terminal.Gui/View/ViewMouse.cs
index 24314f583c..aa190fcf0f 100644
--- a/Terminal.Gui/View/ViewMouse.cs
+++ b/Terminal.Gui/View/ViewMouse.cs
@@ -31,6 +31,25 @@ public partial class View
///
public event EventHandler MouseClick;
+ ///
+ /// Event fired when the user presses and releases the mouse button twice in quick succession without
+ /// moving the mouse outside the view.
+ ///
+ ///
+ ///
+ /// The coordinates are relative to .
+ ///
+ ///
+ public event EventHandler MouseDoubleClick;
+
+ /// Event fired when the user first presses the button down over a view.
+ ///
+ ///
+ /// The coordinates are relative to .
+ ///
+ ///
+ public event EventHandler MouseDown;
+
/// Event fired when the mouse moves into the View's .
public event EventHandler MouseEnter;
@@ -45,6 +64,39 @@ public partial class View
/// Event fired when the mouse leaves the View's .
public event EventHandler MouseLeave;
+ ///
+ /// Event fired when the user moves the mouse over a view, or if mouse was grabbed by the view.
+ /// Flags will indicate if a button is down.
+ ///
+ ///
+ ///
+ /// The coordinates are relative to .
+ ///
+ ///
+ public event EventHandler MouseMove;
+
+ ///
+ /// Event fired when the user presses and releases the mouse button thrice in quick succession without
+ /// moving the mouse outside the view.
+ ///
+ ///
+ ///
+ /// The coordinates are relative to .
+ ///
+ ///
+ public event EventHandler MouseTripleClick;
+
+ ///
+ /// Event fired when the user lets go of the mouse button. Only received if the mouse is over the view,
+ /// or it was grabbed by the view.
+ ///
+ ///
+ ///
+ /// The coordinates are relative to .
+ ///
+ ///
+ public event EventHandler MouseUp;
+
///
/// Processes a . This method is called by when a mouse
/// event occurs.
@@ -87,6 +139,30 @@ public partial class View
return mouseEvent.Handled = true;
}
+ if (mouseEvent.IsMouseDown == true)
+ {
+ if (OnMouseDown (new (mouseEvent)))
+ {
+ return true;
+ }
+ }
+
+ if (mouseEvent.Flags.HasFlag (MouseFlags.ReportMousePosition))
+ {
+ if (OnMouseMove (new (mouseEvent)))
+ {
+ return true;
+ }
+ }
+
+ if (mouseEvent.IsMouseDown == false)
+ {
+ if (OnMouseUp (new (mouseEvent)))
+ {
+ return true;
+ }
+ }
+
if (HighlightStyle != HighlightStyle.None || WantContinuousButtonPressed)
{
if (HandlePressed (mouseEvent))
@@ -109,20 +185,30 @@ public partial class View
|| mouseEvent.Flags.HasFlag (MouseFlags.Button2Clicked)
|| mouseEvent.Flags.HasFlag (MouseFlags.Button3Clicked)
|| mouseEvent.Flags.HasFlag (MouseFlags.Button4Clicked)
- || mouseEvent.Flags.HasFlag (MouseFlags.Button1DoubleClicked)
+ )
+ {
+ // If it's a click, and we didn't handle it, then we'll call OnMouseClick
+ // We get here if the view did not handle the mouse event via OnMouseEvent/MouseEvent and
+ // it did not handle the press/release/clicked events via HandlePress/HandleRelease/HandleClicked
+ return OnMouseClick (new (mouseEvent));
+ }
+
+ if (mouseEvent.Flags.HasFlag (MouseFlags.Button1DoubleClicked)
|| mouseEvent.Flags.HasFlag (MouseFlags.Button2DoubleClicked)
|| mouseEvent.Flags.HasFlag (MouseFlags.Button3DoubleClicked)
|| mouseEvent.Flags.HasFlag (MouseFlags.Button4DoubleClicked)
- || mouseEvent.Flags.HasFlag (MouseFlags.Button1TripleClicked)
+ )
+ {
+ return OnMouseDoubleClick (new (mouseEvent));
+ }
+
+ if (mouseEvent.Flags.HasFlag (MouseFlags.Button1TripleClicked)
|| mouseEvent.Flags.HasFlag (MouseFlags.Button2TripleClicked)
|| mouseEvent.Flags.HasFlag (MouseFlags.Button3TripleClicked)
|| mouseEvent.Flags.HasFlag (MouseFlags.Button4TripleClicked)
)
{
- // If it's a click, and we didn't handle it, then we'll call OnMouseClick
- // We get here if the view did not handle the mouse event via OnMouseEvent/MouseEvent and
- // it did not handle the press/release/clicked events via HandlePress/HandleRelease/HandleClicked
- return OnMouseClick (new (mouseEvent));
+ return OnMouseTripleClick (new (mouseEvent));
}
return false;
@@ -135,6 +221,39 @@ public partial class View
/// if mouse position reports are wanted; otherwise, .
public virtual bool WantMousePositionReports { get; set; }
+ ///
+ /// Called when the user presses and releases the mouse button twice in quick succession without
+ /// moving the mouse outside the view.
+ ///
+ ///
+ ///
+ /// The coordinates are relative to .
+ ///
+ ///
+ ///
+ /// , if the event was handled, otherwise.
+ protected internal virtual bool OnMouseDoubleClick (MouseEventEventArgs args)
+ {
+ MouseDoubleClick?.Invoke (this, args);
+
+ return args.Handled;
+ }
+
+ /// Called when the user first presses the button down over a view's .
+ ///
+ ///
+ /// The coordinates are relative to .
+ ///
+ ///
+ ///
+ /// , if the event was handled, otherwise.
+ protected internal virtual bool OnMouseDown (MouseEventEventArgs args)
+ {
+ MouseDown?.Invoke (this, args);
+
+ return args.Handled;
+ }
+
///
/// Called by when the mouse enters . The view will
/// then receive mouse events until is called indicating the mouse has left
@@ -207,6 +326,60 @@ protected internal virtual bool OnMouseLeave (MouseEvent mouseEvent)
return args.Handled;
}
+ ///
+ /// Called when the user moves the mouse over a view, or if mouse was grabbed by the view.
+ /// Flags will indicate if a button is down.
+ ///
+ ///
+ ///
+ /// The coordinates are relative to .
+ ///
+ ///
+ ///
+ /// , if the event was handled, otherwise.
+ protected internal virtual bool OnMouseMove (MouseEventEventArgs args)
+ {
+ MouseMove?.Invoke (this, args);
+
+ return args.Handled;
+ }
+
+ ///
+ /// Called when the user presses and releases the mouse button thrice in quick succession without
+ /// moving the mouse outside the view.
+ ///
+ ///
+ ///
+ /// The coordinates are relative to .
+ ///
+ ///
+ ///
+ /// , if the event was handled, otherwise.
+ protected internal virtual bool OnMouseTripleClick (MouseEventEventArgs args)
+ {
+ MouseTripleClick?.Invoke (this, args);
+
+ return args.Handled;
+ }
+
+ ///
+ /// Called when the user lets go of the mouse button. Only received if the mouse is over the view,
+ /// or it was grabbed by the view.
+ ///
+ ///
+ ///
+ /// The coordinates are relative to .
+ ///
+ ///
+ ///
+ /// , if the event was handled, otherwise.
+ protected internal virtual bool OnMouseUp (MouseEventEventArgs args)
+ {
+ MouseUp?.Invoke (this, args);
+
+ return args.Handled;
+ }
+
///
/// Called when the view is to be highlighted.
///
@@ -231,11 +404,13 @@ protected internal virtual bool OnMouseLeave (MouseEvent mouseEvent)
return args.Cancel;
}
- /// Invokes the MouseClick event.
+ ///
+ /// Called when the user presses down and then releases the mouse over a view (they could move off in between).
+ /// If they press and release multiple times in quick succession this event will be called for each up action.
+ ///
///
///
- /// Called when the mouse is either clicked or double-clicked. Check
- /// to see which button was clicked.
+ /// The coordinates are relative to .
///
///
/// , if the event was handled, otherwise.
@@ -442,7 +617,7 @@ internal bool SetHighlight (HighlightStyle newHighlightStyle)
// Enable override via virtual method and/or event
HighlightStyle copy = HighlightStyle;
- var args = new CancelEventArgs (ref copy, ref newHighlightStyle);
+ CancelEventArgs args = new CancelEventArgs (ref copy, ref newHighlightStyle);
if (OnHighlight (args) == true)
{
@@ -477,7 +652,8 @@ internal bool SetHighlight (HighlightStyle newHighlightStyle)
var cs = new ColorScheme (ColorScheme)
{
// Highlight the foreground focus color
- Focus = new (ColorScheme.Focus.Foreground.GetHighlightColor (), ColorScheme.Focus.Background.GetHighlightColor ())
+ Focus = new (ColorScheme.Focus.Foreground.GetHighlightColor (), ColorScheme.Focus.Background.GetHighlightColor ()),
+ HotFocus = new (ColorScheme.HotFocus.Foreground.GetHighlightColor (), ColorScheme.HotFocus.Background.GetHighlightColor ())
};
ColorScheme = cs;
}
@@ -486,7 +662,8 @@ internal bool SetHighlight (HighlightStyle newHighlightStyle)
var cs = new ColorScheme (ColorScheme)
{
// Invert Focus color foreground/background. We can do this because we know the view is not going to be focused.
- Normal = new (ColorScheme.Focus.Background, ColorScheme.Normal.Foreground)
+ Normal = new (ColorScheme.Focus.Background, ColorScheme.Normal.Foreground),
+ HotNormal = new (ColorScheme.HotFocus.Background, ColorScheme.HotNormal.Foreground)
};
ColorScheme = cs;
}
diff --git a/UnitTests/Application/MouseTests.cs b/UnitTests/Application/MouseTests.cs
index a3cf2d584d..2cb9e0836e 100644
--- a/UnitTests/Application/MouseTests.cs
+++ b/UnitTests/Application/MouseTests.cs
@@ -401,5 +401,118 @@ public void View_Is_Responsible_For_Calling_UnGrabMouse_Before_Being_Disposed ()
Assert.Equal (0, count);
top.Dispose ();
}
+ [Fact]
+ [AutoInitShutdown]
+ public void Clicked_Event_Only_Occurs_In_The_Same_View_That_Pressed_The_Mouse ()
+ {
+ var view1Clicked = false;
+ var view2Clicked = false;
+ var view1 = new View { Id = "view1", CanFocus = true, Width = 10, Height = 1 };
+ view1.MouseClick += (s, e) => view1Clicked = true;
+ var view2 = new View { Id = "view1", CanFocus = true, Y = 2, Width = 10, Height = 1 };
+ view2.MouseClick += (s, e) => view2Clicked = true;
+ var top = new Toplevel ();
+ top.Add (view1, view2);
+ Application.Begin (top);
+
+ Application.OnMouseEvent (new () { Position = new (0, 0), Flags = MouseFlags.Button1Pressed });
+ Assert.Equal (Application._mouseEnteredView, view1);
+ Assert.Equal (Application._lastViewButtonPressed, view1);
+ Assert.True (Application._canProcessClickedEvent);
+ Assert.True (Application._isMouseDown);
+ Assert.False (view1Clicked);
+ Assert.False (view2Clicked);
+
+ Application.OnMouseEvent (new () { Position = new (0, 2), Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition });
+ Assert.Equal (Application._mouseEnteredView, view2);
+ Assert.Equal (Application._lastViewButtonPressed, view1);
+ Assert.True (Application._canProcessClickedEvent);
+ Assert.Null (Application._isMouseDown);
+ Assert.False (view1Clicked);
+ Assert.False (view2Clicked);
+
+ Application.OnMouseEvent (new () { Position = new (0, 2), Flags = MouseFlags.Button1Released });
+ Assert.Equal (Application._mouseEnteredView, view2);
+ Assert.Null (Application._lastViewButtonPressed);
+ Assert.False (Application._canProcessClickedEvent);
+ Assert.False (Application._isMouseDown);
+ Assert.False (view1Clicked);
+ Assert.False (view2Clicked);
+
+ Application.OnMouseEvent (new () { Position = new (0, 2), Flags = MouseFlags.Button1Clicked });
+ Assert.Equal (Application._mouseEnteredView, view2);
+ Assert.Null (Application._lastViewButtonPressed);
+ Assert.True (Application._canProcessClickedEvent);
+ Assert.Null (Application._isMouseDown);
+ Assert.False (view1Clicked);
+ Assert.False (view2Clicked);
+
+ Application.OnMouseEvent (new () { Position = new (0, 2), Flags = MouseFlags.Button1Pressed });
+ Assert.Equal (Application._mouseEnteredView, view2);
+ Assert.Equal (Application._lastViewButtonPressed, view2);
+ Assert.True (Application._canProcessClickedEvent);
+ Assert.True (Application._isMouseDown);
+ Assert.False (view1Clicked);
+ Assert.False (view2Clicked);
+
+ Application.OnMouseEvent (new () { Position = new (0, 0), Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition });
+ Assert.Equal (Application._mouseEnteredView, view1);
+ Assert.Equal (Application._lastViewButtonPressed, view2);
+ Assert.True (Application._canProcessClickedEvent);
+ Assert.Null (Application._isMouseDown);
+ Assert.False (view1Clicked);
+ Assert.False (view2Clicked);
+
+ Application.OnMouseEvent (new () { Position = new (0, 2), Flags = MouseFlags.Button1Released });
+ Assert.Equal (Application._mouseEnteredView, view2);
+ Assert.Null (Application._lastViewButtonPressed);
+ Assert.True (Application._canProcessClickedEvent);
+ Assert.False (Application._isMouseDown);
+ Assert.False (view1Clicked);
+ Assert.False (view2Clicked);
+
+ Application.OnMouseEvent (new () { Position = new (0, 2), Flags = MouseFlags.Button1Clicked });
+ Assert.Equal (Application._mouseEnteredView, view2);
+ Assert.Null (Application._lastViewButtonPressed);
+ Assert.True (Application._canProcessClickedEvent);
+ Assert.Null (Application._isMouseDown);
+ Assert.False (view1Clicked);
+ Assert.True (view2Clicked);
+
+ Application.OnMouseEvent (new () { Position = new (0, 0), Flags = MouseFlags.Button1Pressed });
+ Assert.Equal (Application._mouseEnteredView, view1);
+ Assert.Equal (Application._lastViewButtonPressed, view1);
+ Assert.True (Application._canProcessClickedEvent);
+ Assert.True (Application._isMouseDown);
+ Assert.False (view1Clicked);
+ Assert.True (view2Clicked);
+
+ Application.OnMouseEvent (new () { Position = new (0, 2), Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition });
+ Assert.Equal (Application._mouseEnteredView, view2);
+ Assert.Equal (Application._lastViewButtonPressed, view1);
+ Assert.True (Application._canProcessClickedEvent);
+ Assert.Null (Application._isMouseDown);
+ Assert.False (view1Clicked);
+ Assert.True (view2Clicked);
+
+ Application.OnMouseEvent (new () { Position = new (0, 0), Flags = MouseFlags.Button1Released });
+ Assert.Equal (Application._mouseEnteredView, view1);
+ Assert.Null (Application._lastViewButtonPressed);
+ Assert.True (Application._canProcessClickedEvent);
+ Assert.False (Application._isMouseDown);
+ Assert.False (view1Clicked);
+ Assert.True (view2Clicked);
+
+ Application.OnMouseEvent (new () { Position = new (0, 0), Flags = MouseFlags.Button1Clicked });
+ Assert.Equal (Application._mouseEnteredView, view1);
+ Assert.Null (Application._lastViewButtonPressed);
+ Assert.True (Application._canProcessClickedEvent);
+ Assert.Null (Application._isMouseDown);
+ Assert.True (view1Clicked);
+ Assert.True (view2Clicked);
+
+ top.Dispose ();
+ }
+
#endregion
}
diff --git a/UnitTests/View/MouseTests.cs b/UnitTests/View/MouseTests.cs
index a0bef94f58..2e43c9bc37 100644
--- a/UnitTests/View/MouseTests.cs
+++ b/UnitTests/View/MouseTests.cs
@@ -646,4 +646,53 @@ void View_Highlight (object sender, CancelEventArgs e)
}
}
}
+
+ [Fact]
+ [AutoInitShutdown]
+ public void Test_All_Mouse_Events ()
+ {
+ var onMouseEvent = false;
+ var onMouseDown = false;
+ var onMouseMove = false;
+ var onMouseUp = false;
+ var onMouseClick = false;
+ var onMouseDoubleClick = false;
+ var onMouseTripleClick = false;
+
+ var view = new View { CanFocus = true, Width = 10, Height = 1};
+ view.MouseEvent += (s, e) => onMouseEvent = true;
+ view.MouseDown += (s, e) => onMouseDown = true;
+ view.MouseMove += (s, e) => onMouseMove = true;
+ view.MouseUp += (s, e) => onMouseUp = true;
+ view.MouseClick += (s, e) => onMouseClick = true;
+ view.MouseDoubleClick += (s, e) => onMouseDoubleClick = true;
+ view.MouseTripleClick += (s, e) => onMouseTripleClick = true;
+
+ var top = new Toplevel ();
+ top.Add (view);
+ Application.Begin (top);
+
+ Application.OnMouseEvent (new () { Position = new (0, 0), Flags = MouseFlags.WheeledDown });
+ Assert.True (onMouseEvent);
+
+ Application.OnMouseEvent (new () { Position = new (0, 0), Flags = MouseFlags.Button1Pressed });
+ Assert.True (onMouseDown);
+
+ Application.OnMouseEvent (new () { Position = new (0, 0), Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition });
+ Assert.True (onMouseMove);
+
+ Application.OnMouseEvent (new () { Position = new (0, 0), Flags = MouseFlags.Button1Released });
+ Assert.True (onMouseUp);
+
+ Application.OnMouseEvent (new () { Position = new (0, 0), Flags = MouseFlags.Button1Clicked });
+ Assert.True (onMouseClick);
+
+ Application.OnMouseEvent (new () { Position = new (0, 0), Flags = MouseFlags.Button1DoubleClicked });
+ Assert.True (onMouseDoubleClick);
+
+ Application.OnMouseEvent (new () { Position = new (0, 0), Flags = MouseFlags.Button1TripleClicked });
+ Assert.True (onMouseTripleClick);
+
+ top.Dispose ();
+ }
}
diff --git a/UnitTests/Views/ButtonTests.cs b/UnitTests/Views/ButtonTests.cs
index 4ef86d3875..c97ff8439e 100644
--- a/UnitTests/Views/ButtonTests.cs
+++ b/UnitTests/Views/ButtonTests.cs
@@ -684,4 +684,45 @@ public void WantContinuousButtonPressed_True_ButtonPressRelease_Accepts (MouseFl
button.Dispose ();
}
+ [Fact]
+ [AutoInitShutdown]
+ public void WantMousePositionReports_False_And_WantContinuousButtonPressed_False_Focus_The_Another_Button_On_Mouse_Pressed_Released ()
+ {
+ var button1 = new Button { Text = "Button1" };
+ var acceptCount = 0;
+ button1.Accept += (s, e) => acceptCount++;
+ var button2 = new Button { Text = "Button2", X = Pos.Right (button1) + 1 };
+ button2.Accept += (s, e) => acceptCount++;
+ var top = new Toplevel ();
+ top.Add (button1, button2);
+ Application.Begin (top);
+
+ Assert.True (button1.HasFocus);
+ Application.OnMouseEvent (new () { Position = new (0, 0), Flags = MouseFlags.Button1Pressed });
+ Assert.Equal (button1, Application.MouseGrabView);
+ Assert.Equal (0, acceptCount);
+ Assert.True (button1.HasFocus);
+
+ Application.OnMouseEvent (new () { Position = new (13, 0), Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition});
+ Assert.Equal (button2, Application.MouseGrabView);
+ Assert.Equal (0, acceptCount);
+ Assert.True (button2.HasFocus);
+
+ Application.OnMouseEvent (new () { Position = new (13, 0), Flags = MouseFlags.Button1Released });
+ Assert.Equal (button2, Application.MouseGrabView);
+ Assert.Equal (0, acceptCount);
+ Assert.True (button2.HasFocus);
+
+ Application.OnMouseEvent (new () { Position = new (13, 0), Flags = MouseFlags.Button1Clicked });
+ Assert.Equal (button2, Application.MouseGrabView);
+ Assert.Equal (0, acceptCount);
+ Assert.True (button2.HasFocus);
+
+ Application.OnMouseEvent (new () { Position = new (13, 0), Flags = MouseFlags.Button1Clicked });
+ Assert.Null (Application.MouseGrabView);
+ Assert.Equal (1, acceptCount);
+ Assert.True (button2.HasFocus);
+
+ top.Dispose ();
+ }
}
\ No newline at end of file