Refactored MouseEnter/Leave APIs to match design guidelines

This commit is contained in:
Tig
2024-04-06 08:15:57 -04:00
parent cca32726fc
commit 40ae272944
5 changed files with 89 additions and 18 deletions

View File

@@ -1486,7 +1486,7 @@ public static partial class Application
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?.OnMouseLeave (mouseEvent);
_mouseEnteredView?.NewMouseLeaveEvent (mouseEvent);
}
//System.Diagnostics.Debug.WriteLine ($"{nme.Flags};{nme.X};{nme.Y};{mouseGrabView}");
@@ -1568,12 +1568,12 @@ public static partial class Application
if (_mouseEnteredView is null)
{
_mouseEnteredView = view;
view.OnMouseEnter (me);
view.NewMouseEnterEvent (me);
}
else if (_mouseEnteredView != view)
{
_mouseEnteredView.OnMouseLeave (me);
view.OnMouseEnter (me);
_mouseEnteredView.NewMouseLeaveEvent (me);
view.NewMouseEnterEvent (me);
_mouseEnteredView = view;
}

View File

@@ -29,6 +29,9 @@ public enum HighlightStyle
PressedOutside = 4
}
/// <summary>
/// Event arguments for the <see cref="View.Highlight"/> event.
/// </summary>
public class HighlightEventArgs : CancelEventArgs
{
public HighlightEventArgs (HighlightStyle style)
@@ -36,6 +39,9 @@ public class HighlightEventArgs : CancelEventArgs
HighlightStyle = style;
}
/// <summary>
/// The highlight style.
/// </summary>
public HighlightStyle HighlightStyle { get; }
}
@@ -55,16 +61,24 @@ public partial class View
public virtual bool WantMousePositionReports { get; set; }
/// <summary>
/// Called when the mouse enters the View's <see cref="Bounds"/>. The view will now receive mouse events until the
/// mouse leaves
/// the view. At which time, <see cref="OnMouseLeave(Gui.MouseEvent)"/> will be called.
/// Called by <see cref="Application.OnMouseEvent"/> when the mouse enters <see cref="Bounds"/>. The view will
/// then receive mouse events until <see cref="NewMouseLeaveEvent"/> is called indicating the mouse has left
/// the view.
/// </summary>
/// <remarks>
/// The coordinates are relative to <see cref="View.Bounds"/>.
/// <para>
/// A view must be both enabled and visible to receive mouse events.
/// </para>
/// <para>
/// This method calls <see cref="OnMouseEnter"/> to fire the event.
/// </para>
/// <para>
/// See <see cref="SetHighlight"/> for more information.
/// </para>
/// </remarks>
/// <param name="mouseEvent"></param>
/// <returns><see langword="true"/>, if the event was handled, <see langword="false"/> otherwise.</returns>
protected internal virtual bool OnMouseEnter (MouseEvent mouseEvent)
/// <returns><see langword="true"/> if the event was handled, <see langword="false"/> otherwise.</returns>
internal bool? NewMouseEnterEvent (MouseEvent mouseEvent)
{
if (!Enabled)
{
@@ -76,6 +90,27 @@ public partial class View
return false;
}
return OnMouseEnter (mouseEvent);
}
/// <summary>
/// Called by <see cref="NewMouseEvent"/> when the mouse enters <see cref="Bounds"/>. The view will
/// then receive mouse events until <see cref="OnMouseLeave"/> is called indicating the mouse has left
/// the view.
/// </summary>
/// <remarks>
/// <para>
/// Override this method or subscribe to <see cref="MouseEnter"/> to change the default enter behavior.
/// </para>
/// <para>
/// The coordinates are relative to <see cref="View.Bounds"/>.
/// </para>
/// </remarks>
/// <param name="mouseEvent"></param>
/// <returns><see langword="true"/>, if the event was handled, <see langword="false"/> otherwise.</returns>
protected internal virtual bool OnMouseEnter (MouseEvent mouseEvent)
{
var args = new MouseEventEventArgs (mouseEvent);
MouseEnter?.Invoke (this, args);
@@ -85,13 +120,49 @@ public partial class View
/// <summary>Event fired when the mouse moves into the View's <see cref="Bounds"/>.</summary>
public event EventHandler<MouseEventEventArgs> MouseEnter;
/// <summary>
/// Called when the mouse has moved out of the View's <see cref="Bounds"/>. The view will no longer receive mouse
/// events (until the
/// mouse moves within the view again and <see cref="OnMouseEnter(Gui.MouseEvent)"/> is called).
/// Called by <see cref="Application.OnMouseEvent"/> when the mouse leaves <see cref="Bounds"/>. The view will
/// then no longer receive mouse events.
/// </summary>
/// <remarks>
/// <para>
/// A view must be both enabled and visible to receive mouse events.
/// </para>
/// <para>
/// This method calls <see cref="OnMouseLeave"/> to fire the event.
/// </para>
/// <para>
/// See <see cref="SetHighlight"/> for more information.
/// </para>
/// </remarks>
/// <param name="mouseEvent"></param>
/// <returns><see langword="true"/> if the event was handled, <see langword="false"/> otherwise.</returns>
internal bool? NewMouseLeaveEvent (MouseEvent mouseEvent)
{
if (!Enabled)
{
return true;
}
if (!CanBeVisible (this))
{
return false;
}
return OnMouseLeave (mouseEvent);
}
/// <summary>
/// Called by <see cref="NewMouseEvent"/> when a mouse leaves <see cref="Bounds"/>. The view will
/// no longer receive mouse events.
/// </summary>
/// <remarks>
/// <para>
/// Override this method or subscribe to <see cref="MouseEnter"/> to change the default leave behavior.
/// </para>
/// <para>
/// The coordinates are relative to <see cref="View.Bounds"/>.
/// </para>
/// </remarks>
/// <param name="mouseEvent"></param>
/// <returns><see langword="true"/>, if the event was handled, <see langword="false"/> otherwise.</returns>

View File

@@ -444,7 +444,7 @@ public partial class Toplevel : View
/// perform tasks when the <see cref="Toplevel"/> has been laid out and focus has been set. changes.
/// <para>
/// A Ready event handler is a good place to finalize initialization after calling
/// <see cref="Application.Run(Func{Exception, bool})"/> on this <see cref="Toplevel"/>.
/// <see cref="Application.Run(Toplevel, Func{Exception, bool}, ConsoleDriver)"/> on this <see cref="Toplevel"/>.
/// </para>
/// </summary>
public event EventHandler Ready;

View File

@@ -235,8 +235,8 @@ public class ResponderTests
Assert.False (r.OnKeyDown (new Key { KeyCode = KeyCode.Null }));
Assert.False (r.OnKeyUp (new Key { KeyCode = KeyCode.Null }));
Assert.False (r.NewMouseEvent (new MouseEvent { Flags = MouseFlags.AllEvents }));
Assert.False (r.OnMouseEnter (new MouseEvent { Flags = MouseFlags.AllEvents }));
Assert.False (r.OnMouseLeave (new MouseEvent { Flags = MouseFlags.AllEvents }));
Assert.False (r.NewMouseEnterEvent (new MouseEvent { Flags = MouseFlags.AllEvents }));
Assert.False (r.NewMouseLeaveEvent (new MouseEvent { Flags = MouseFlags.AllEvents }));
var v = new View ();
Assert.False (r.OnEnter (v));

View File

@@ -866,8 +866,8 @@ At 0,0
//Assert.False (r.OnKeyDown (new KeyEventArgs () { Key = Key.Unknown }));
Assert.False (r.OnKeyUp (new Key { KeyCode = KeyCode.Null }));
Assert.False (r.NewMouseEvent (new MouseEvent { Flags = MouseFlags.AllEvents }));
Assert.False (r.OnMouseEnter (new MouseEvent { Flags = MouseFlags.AllEvents }));
Assert.False (r.OnMouseLeave (new MouseEvent { Flags = MouseFlags.AllEvents }));
Assert.False (r.NewMouseEnterEvent (new MouseEvent { Flags = MouseFlags.AllEvents }));
Assert.False (r.NewMouseLeaveEvent (new MouseEvent { Flags = MouseFlags.AllEvents }));
var v1 = new View ();
Assert.False (r.OnEnter (v1));