Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #3312. Mouse API makes it way too hard to track button pressed. #3393

Draft
wants to merge 19 commits into
base: v2_develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 60 additions & 8 deletions Terminal.Gui/Application.cs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@

// Mouse
_mouseEnteredView = null;
_lastViewButtonPressed = null;
_canProcessClickedEvent = true;
_isMouseDown = false;
BDisp marked this conversation as resolved.
Show resolved Hide resolved
WantContinuousButtonPressedView = null;
MouseEvent = null;
GrabbedMouse = null;
Expand Down Expand Up @@ -1432,6 +1435,9 @@

// Used by OnMouseEvent to track the last view that was clicked on.
internal static View? _mouseEnteredView;
internal static View? _lastViewButtonPressed;
BDisp marked this conversation as resolved.
Show resolved Hide resolved
internal static bool _canProcessClickedEvent = true;
internal static bool? _isMouseDown;

/// <summary>Event fired when a mouse move or click occurs. Coordinates are screen relative.</summary>
/// <remarks>
Expand All @@ -1441,12 +1447,12 @@
/// </para>
/// <para>The <see cref="MouseEvent.View"/> will contain the <see cref="View"/> that contains the mouse coordinates.</para>
/// </remarks>
public static event EventHandler<MouseEvent> MouseEvent;

Check warning on line 1450 in Terminal.Gui/Application.cs

View workflow job for this annotation

GitHub Actions / build_and_test

Non-nullable event 'MouseEvent' must contain a non-null value when exiting constructor. Consider declaring the event as nullable.

/// <summary>Called when a mouse event occurs. Raises the <see cref="MouseEvent"/> event.</summary>
/// <remarks>This method can be used to simulate a mouse event, e.g. in unit tests.</remarks>
/// <param name="a">The mouse event with coordinates relative to the screen.</param>

Check warning on line 1454 in Terminal.Gui/Application.cs

View workflow job for this annotation

GitHub Actions / build_and_test

XML comment has a param tag for 'a', but there is no parameter by that name
internal static void OnMouseEvent (MouseEvent mouseEvent)

Check warning on line 1455 in Terminal.Gui/Application.cs

View workflow job for this annotation

GitHub Actions / build_and_test

Parameter 'mouseEvent' has no matching param tag in the XML comment for 'Application.OnMouseEvent(MouseEvent)' (but other parameters do)
{
if (IsMouseDisabled)
{
Expand All @@ -1461,6 +1467,38 @@
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)
Expand All @@ -1480,13 +1518,18 @@
Y = boundsLoc.Y,
Flags = mouseEvent.Flags,
ScreenPosition = new (mouseEvent.X, mouseEvent.Y),
View = MouseGrabView
View = view ?? MouseGrabView,
IsMouseDown = _isMouseDown
};

if (MouseGrabView.Bounds.Contains (viewRelativeMouseEvent.X, viewRelativeMouseEvent.Y) is false)
{
// The mouse has moved outside the bounds of the view that grabbed the mouse
_mouseEnteredView?.NewMouseLeaveEvent (mouseEvent);
// Give a chance for the current view process the event
if (ProcessMouseEvent (mouseEvent, view))
{
return;
}
}

//System.Diagnostics.Debug.WriteLine ($"{nme.Flags};{nme.X};{nme.Y};{mouseGrabView}");
Expand All @@ -1496,6 +1539,11 @@
}
}

ProcessMouseEvent (mouseEvent, view);
}

private static bool ProcessMouseEvent (MouseEvent mouseEvent, View? view)
{
if (view is { WantContinuousButtonPressed: true })
{
WantContinuousButtonPressedView = view;
Expand All @@ -1521,14 +1569,14 @@

if (view is { } && view != OverlappedTop && top != Current)
{
MoveCurrent ((Toplevel)top);

Check warning on line 1572 in Terminal.Gui/Application.cs

View workflow job for this annotation

GitHub Actions / build_and_test

Converting null literal or possible null value to non-nullable type.
}
}
}

if (view is null)
{
return;
return false;
}

MouseEvent? me = null;
Expand All @@ -1543,7 +1591,8 @@
Y = frameLoc.Y,
Flags = mouseEvent.Flags,
ScreenPosition = new (mouseEvent.X, mouseEvent.Y),
View = view
View = view,
IsMouseDown = _isMouseDown
};
}
else if (view.BoundsToScreen (view.Bounds).Contains (mouseEvent.X, mouseEvent.Y))
Expand All @@ -1556,13 +1605,14 @@
Y = boundsPoint.Y,
Flags = mouseEvent.Flags,
ScreenPosition = new (mouseEvent.X, mouseEvent.Y),
View = view
View = view,
IsMouseDown = _isMouseDown
};
}

if (me is null)
{
return;
return false;
}

if (_mouseEnteredView is null)
Expand All @@ -1579,7 +1629,7 @@

if (!view.WantMousePositionReports && mouseEvent.Flags == MouseFlags.ReportMousePosition)
{
return;
return false;
}

WantContinuousButtonPressedView = view.WantContinuousButtonPressed ? view : null;
Expand All @@ -1589,10 +1639,12 @@
if (view.NewMouseEvent (me) == false)
{
// Should we bubble up the event, if it is not handled?
//return;
return false;
}

BringOverlappedTopToFront ();

return true;
}
#nullable restore

Expand Down
5 changes: 5 additions & 0 deletions Terminal.Gui/Input/Mouse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,16 @@
/// mouse has moved.
/// </para>
/// <para>
/// Calculated and processed in <see cref="Application.OnMouseEvent(MouseEventEventArgs)"/>.

Check warning on line 141 in Terminal.Gui/Input/Mouse.cs

View workflow job for this annotation

GitHub Actions / build_and_test

XML comment has cref attribute 'OnMouseEvent(MouseEventEventArgs)' that could not be resolved
/// </para>
/// </remarks>
public Point ScreenPosition { get; set; }

/// <summary>
/// Indicates if the current mouse event has first pressed <see langword="true"/>, latest released <see langword="false"/> or none <see langword="null"/>.
/// </summary>
public bool? IsMouseDown { get; set; }
BDisp marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>Returns a <see cref="T:System.String"/> that represents the current <see cref="MouseEvent"/>.</summary>
/// <returns>A <see cref="T:System.String"/> that represents the current <see cref="MouseEvent"/>.</returns>
public override string ToString () { return $"({X},{Y}):{Flags}"; }
Expand Down
Loading
Loading