|
@@ -1,5 +1,6 @@
|
|
|
-#nullable enable
|
|
|
+#nullable enable
|
|
|
namespace Terminal.Gui;
|
|
|
+
|
|
|
public static partial class Application // Mouse handling
|
|
|
{
|
|
|
#region Mouse handling
|
|
@@ -36,16 +37,13 @@ public static partial class Application // Mouse handling
|
|
|
/// <param name="view">View that will receive all mouse events until <see cref="UngrabMouse"/> is invoked.</param>
|
|
|
public static void GrabMouse (View? view)
|
|
|
{
|
|
|
- if (view is null)
|
|
|
+ if (view is null || OnGrabbingMouse (view))
|
|
|
{
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- if (!OnGrabbingMouse (view))
|
|
|
- {
|
|
|
- OnGrabbedMouse (view);
|
|
|
- MouseGrabView = view;
|
|
|
- }
|
|
|
+ OnGrabbedMouse (view);
|
|
|
+ MouseGrabView = view;
|
|
|
}
|
|
|
|
|
|
/// <summary>Releases the mouse grab, so mouse events will be routed to the view on which the mouse is.</summary>
|
|
@@ -56,6 +54,10 @@ public static partial class Application // Mouse handling
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+#if DEBUG_IDISPOSABLE
|
|
|
+ ObjectDisposedException.ThrowIf (MouseGrabView.WasDisposed, MouseGrabView);
|
|
|
+#endif
|
|
|
+
|
|
|
if (!OnUnGrabbingMouse (MouseGrabView))
|
|
|
{
|
|
|
View view = MouseGrabView;
|
|
@@ -64,6 +66,7 @@ public static partial class Application // Mouse handling
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /// <exception cref="Exception">A delegate callback throws an exception.</exception>
|
|
|
private static bool OnGrabbingMouse (View? view)
|
|
|
{
|
|
|
if (view is null)
|
|
@@ -77,6 +80,7 @@ public static partial class Application // Mouse handling
|
|
|
return evArgs.Cancel;
|
|
|
}
|
|
|
|
|
|
+ /// <exception cref="Exception">A delegate callback throws an exception.</exception>
|
|
|
private static bool OnUnGrabbingMouse (View? view)
|
|
|
{
|
|
|
if (view is null)
|
|
@@ -90,6 +94,7 @@ public static partial class Application // Mouse handling
|
|
|
return evArgs.Cancel;
|
|
|
}
|
|
|
|
|
|
+ /// <exception cref="Exception">A delegate callback throws an exception.</exception>
|
|
|
private static void OnGrabbedMouse (View? view)
|
|
|
{
|
|
|
if (view is null)
|
|
@@ -100,6 +105,7 @@ public static partial class Application // Mouse handling
|
|
|
GrabbedMouse?.Invoke (view, new (view));
|
|
|
}
|
|
|
|
|
|
+ /// <exception cref="Exception">A delegate callback throws an exception.</exception>
|
|
|
private static void OnUnGrabbedMouse (View? view)
|
|
|
{
|
|
|
if (view is null)
|
|
@@ -110,8 +116,6 @@ public static partial class Application // Mouse handling
|
|
|
UnGrabbedMouse?.Invoke (view, new (view));
|
|
|
}
|
|
|
|
|
|
-#nullable enable
|
|
|
-
|
|
|
// Used by OnMouseEvent to track the last view that was clicked on.
|
|
|
internal static View? MouseEnteredView { get; set; }
|
|
|
|
|
@@ -166,51 +170,49 @@ public static partial class Application // Mouse handling
|
|
|
if ((MouseGrabView.Viewport with { Location = Point.Empty }).Contains (viewRelativeMouseEvent.Position) is false)
|
|
|
{
|
|
|
// The mouse has moved outside the bounds of the view that grabbed the mouse
|
|
|
- MouseGrabView?.NewMouseLeaveEvent (mouseEvent);
|
|
|
+ MouseGrabView.NewMouseLeaveEvent (mouseEvent);
|
|
|
}
|
|
|
|
|
|
//System.Diagnostics.Debug.WriteLine ($"{nme.Flags};{nme.X};{nme.Y};{mouseGrabView}");
|
|
|
- if (MouseGrabView?.NewMouseEvent (viewRelativeMouseEvent) == true)
|
|
|
+ if (MouseGrabView.NewMouseEvent (viewRelativeMouseEvent) is true)
|
|
|
{
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (view is { WantContinuousButtonPressed: true })
|
|
|
+ // We can combine this into the switch expression to reduce cognitive complexity even more and likely
|
|
|
+ // avoid one or two of these checks in the process, as well.
|
|
|
+ WantContinuousButtonPressedView = view switch
|
|
|
+ {
|
|
|
+ { WantContinuousButtonPressed: true } => view,
|
|
|
+ _ => null
|
|
|
+ };
|
|
|
+
|
|
|
+ if (view is not Adornment
|
|
|
+ && (view is null || view == ApplicationOverlapped.OverlappedTop)
|
|
|
+ && Current is { Modal: false }
|
|
|
+ && ApplicationOverlapped.OverlappedTop != null
|
|
|
+ && mouseEvent.Flags is not MouseFlags.ReportMousePosition and not 0)
|
|
|
{
|
|
|
- WantContinuousButtonPressedView = view;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- WantContinuousButtonPressedView = null;
|
|
|
- }
|
|
|
+ // This occurs when there are multiple overlapped "tops"
|
|
|
+ // E.g. "Mdi" - in the Background Worker Scenario
|
|
|
+ View? top = ApplicationOverlapped.FindDeepestTop (Top!, mouseEvent.Position);
|
|
|
+ view = View.FindDeepestView (top, mouseEvent.Position);
|
|
|
|
|
|
- if (view is not Adornment)
|
|
|
- {
|
|
|
- if ((view is null || view == ApplicationOverlapped.OverlappedTop)
|
|
|
- && Current is { Modal: false }
|
|
|
- && ApplicationOverlapped.OverlappedTop != null
|
|
|
- && mouseEvent.Flags != MouseFlags.ReportMousePosition
|
|
|
- && mouseEvent.Flags != 0)
|
|
|
+ if (view is { } && view != ApplicationOverlapped.OverlappedTop && top != Current && top is { })
|
|
|
{
|
|
|
- // This occurs when there are multiple overlapped "tops"
|
|
|
- // E.g. "Mdi" - in the Background Worker Scenario
|
|
|
- View? top = ApplicationOverlapped.FindDeepestTop (Top!, mouseEvent.Position);
|
|
|
- view = View.FindDeepestView (top, mouseEvent.Position);
|
|
|
-
|
|
|
- if (view is { } && view != ApplicationOverlapped.OverlappedTop && top != Current && top is { })
|
|
|
- {
|
|
|
- ApplicationOverlapped.MoveCurrent ((Toplevel)top);
|
|
|
- }
|
|
|
+ ApplicationOverlapped.MoveCurrent ((Toplevel)top);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // May be null before the prior condition or the condition may set it as null.
|
|
|
+ // So, the checking must be outside the prior condition.
|
|
|
if (view is null)
|
|
|
{
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- MouseEvent? me = null;
|
|
|
+ MouseEvent? me;
|
|
|
|
|
|
if (view is Adornment adornment)
|
|
|
{
|
|
@@ -236,8 +238,7 @@ public static partial class Application // Mouse handling
|
|
|
View = view
|
|
|
};
|
|
|
}
|
|
|
-
|
|
|
- if (me is null)
|
|
|
+ else
|
|
|
{
|
|
|
return;
|
|
|
}
|
|
@@ -263,13 +264,8 @@ public static partial class Application // Mouse handling
|
|
|
|
|
|
//Debug.WriteLine ($"OnMouseEvent: ({a.MouseEvent.X},{a.MouseEvent.Y}) - {a.MouseEvent.Flags}");
|
|
|
|
|
|
- while (view.NewMouseEvent (me) != true)
|
|
|
+ while (view.NewMouseEvent (me) is not true && MouseGrabView is not { })
|
|
|
{
|
|
|
- if (MouseGrabView is { })
|
|
|
- {
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
if (view is Adornment adornmentView)
|
|
|
{
|
|
|
view = adornmentView.Parent!.SuperView;
|