Files
Terminal.Gui/Tests/UnitTests/View/Mouse/MouseTests.cs
Copilot 4974343e74 Fixes #4317 - Refactor Application.Mouse for decoupling and parallelism (#4318)
* Initial plan

* Refactor Application.Mouse - Create IMouse interface and Mouse implementation

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Add enhanced documentation for Application.Mouse property

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Add parallelizable unit tests for IMouse interface

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Refactor Application.Mouse for decoupling and parallelism

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Move HandleMouseGrab method to IMouseGrabHandler interface

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Add parallelizable tests for IMouse and IMouseGrabHandler interfaces

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Add MouseEventRoutingTests - 27 parallelizable tests for View mouse event handling

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Fix terminology: Replace parent/child with superView/subView in MouseEventRoutingTests

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Fix coding standards: Use explicit types and target-typed new() in test files

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Update coding standards documentation with explicit var and target-typed new() guidance

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Refactor Application classes and improve maintainability

Refactored `Sixel` property to be immutable, enhancing thread safety.
Cleaned up `ApplicationImpl` by removing redundant fields, restructuring
methods (`CreateDriver`, `CreateSubcomponents`), and improving exception
handling. Updated `Run<T>` and `Shutdown` methods for consistency.

Standardized logging/debugging messages and fixed formatting issues.
Reorganized `IApplication` interface, added detailed XML documentation,
and grouped related methods logically.

Performed general code cleanup, including fixing typos, improving
readability, and removing legacy/unnecessary code to reduce technical debt.

* Code cleanup

* Remove unreferenced LayoutAndDraw method from ApplicationImpl

* Code cleanup and TODOs

- Updated namespaces to reflect the new structure.
- Added `Driver`, `Force16Colors`, and `ForceDriver` properties.
- Introduced `Sixel` collection for sixel image management.
- Added lifecycle methods: `GetDriverTypes`, `Shutdown`, and events.
- Refactored `Init` to support legacy and modern drivers.
- Improved driver event handling and screen abstraction.
- Updated `Run` method to align with the application lifecycle.
- Simplified `IConsoleDriver` documentation.
- Removed redundant methods and improved code readability.

* Refactor LayoutAndDraw logic for better encapsulation

Refactored `Application.Run` to delegate `LayoutAndDraw` to
`ApplicationImpl.Instance.LayoutAndDraw`, improving separation
of concerns. Renamed `forceDraw` to `forceRedraw` for clarity
and moved `LayoutAndDraw` implementation to `ApplicationImpl`.

Added a new `LayoutAndDraw` method in `ApplicationImpl` to
handle layout and drawing, including managing `TopLevels`,
handling active popovers, and refreshing the screen. Updated
the `IApplication` interface to reflect the new method and
improved its documentation.

Implemented `RequestStop` in `ApplicationImpl` and fixed
formatting inconsistencies in `Run<T>`. Added TODOs for future
refactoring to encapsulate `Top` and `TopLevels` into an
`IViewHierarchy` and move certain properties to `IApplication`.

* Refactor ApplicationImpl to enhance mouse and keyboard support

Added a new `Mouse` property to the `ApplicationImpl` class,
replacing its previous declaration, to improve mouse
functionality. Updated `MouseGrabHandler` to initialize with
a default instance of `MouseGrabHandler`.

Added comments to ensure the preservation of existing keyboard
settings (`QuitKey`, `ArrangeKey`, `NextTabKey`) for backward
compatibility. These changes enhance clarity, functionality,
and maintainability of the class.

* Merge IMouseGrabHandler into IMouse - consolidate mouse handling into single interface

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Rename Mouse to MouseImpl and Keyboard to KeyboardImpl for consistency

Co-authored-by: tig <585482+tig@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: tig <585482+tig@users.noreply.github.com>
Co-authored-by: Tig <tig@users.noreply.github.com>
2025-10-25 08:48:26 -06:00

686 lines
23 KiB
C#

using Moq;
using UnitTests;
namespace UnitTests.ViewMouseTests;
[Trait ("Category", "Input")]
public class MouseTests : TestsAllViews
{
// TODO: Add more tests that ensure the above test works with positive adornments
// Test drag to move
[Theory]
[InlineData (0, 0, 0, 0, false)]
[InlineData (0, 0, 0, 4, false)]
[InlineData (1, 0, 0, 4, false)]
[InlineData (0, 1, 0, 4, true)]
[InlineData (0, 0, 1, 4, false)]
[InlineData (1, 1, 0, 3, false)]
[InlineData (1, 1, 0, 4, false)]
[InlineData (1, 1, 0, 5, true)]
[InlineData (1, 1, 0, 6, false)]
[InlineData (1, 1, 0, 11, false)]
[InlineData (1, 1, 0, 12, true)]
[InlineData (1, 1, 0, 13, false)]
[InlineData (1, 1, 0, 14, false)]
[AutoInitShutdown]
public void ButtonPressed_In_Border_Starts_Drag (int marginThickness, int borderThickness, int paddingThickness, int xy, bool expectedMoved)
{
var testView = new View
{
CanFocus = true,
X = 4,
Y = 4,
Width = 10,
Height = 10,
Arrangement = ViewArrangement.Movable
};
testView.Margin.Thickness = new (marginThickness);
testView.Border.Thickness = new (borderThickness);
testView.Padding.Thickness = new (paddingThickness);
var top = new Toplevel ();
top.Add (testView);
RunState rs = Application.Begin (top);
Assert.Equal (4, testView.Frame.X);
Assert.Equal (new (4, 4), testView.Frame.Location);
Application.RaiseMouseEvent (new () { ScreenPosition = new (xy, xy), Flags = MouseFlags.Button1Pressed });
Application.RaiseMouseEvent (new () { ScreenPosition = new (xy + 1, xy + 1), Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition });
AutoInitShutdownAttribute.RunIteration ();
Assert.Equal (expectedMoved, new Point (5, 5) == testView.Frame.Location);
top.Dispose ();
}
[Theory]
[InlineData (MouseFlags.Button1Pressed, MouseFlags.Button1Released, MouseFlags.Button1Clicked)]
[InlineData (MouseFlags.Button2Pressed, MouseFlags.Button2Released, MouseFlags.Button2Clicked)]
[InlineData (MouseFlags.Button3Pressed, MouseFlags.Button3Released, MouseFlags.Button3Clicked)]
[InlineData (MouseFlags.Button4Pressed, MouseFlags.Button4Released, MouseFlags.Button4Clicked)]
public void WantContinuousButtonPressed_False_Button_Press_Release_DoesNotClick (MouseFlags pressed, MouseFlags released, MouseFlags clicked)
{
var me = new MouseEventArgs ();
var view = new View
{
Width = 1,
Height = 1,
WantContinuousButtonPressed = false
};
var clickedCount = 0;
view.MouseClick += (s, e) => clickedCount++;
me.Flags = pressed;
view.NewMouseEvent (me);
Assert.Equal (0, clickedCount);
me.Handled = false;
me.Flags = pressed;
view.NewMouseEvent (me);
Assert.Equal (0, clickedCount);
me.Handled = false;
me.Flags = released;
view.NewMouseEvent (me);
Assert.Equal (0, clickedCount);
me.Handled = false;
me.Flags = clicked;
view.NewMouseEvent (me);
Assert.Equal (1, clickedCount);
view.Dispose ();
// Button1Pressed, Button1Released cause Application.Mouse.MouseGrabView to be set
Application.ResetState (true);
}
[Theory]
[InlineData (MouseFlags.Button1Clicked)]
[InlineData (MouseFlags.Button2Clicked)]
[InlineData (MouseFlags.Button3Clicked)]
[InlineData (MouseFlags.Button4Clicked)]
public void WantContinuousButtonPressed_True_Button_Clicked_Raises_MouseClick (MouseFlags clicked)
{
var me = new MouseEventArgs ();
var view = new View
{
Width = 1,
Height = 1,
WantContinuousButtonPressed = true
};
var clickedCount = 0;
view.MouseClick += (s, e) => clickedCount++;
me.Flags = clicked;
view.NewMouseEvent (me);
Assert.Equal (1, clickedCount);
view.Dispose ();
// Button1Pressed, Button1Released cause Application.Mouse.MouseGrabView to be set
Application.ResetState (true);
}
[Theory]
[InlineData (MouseFlags.Button1Clicked)]
[InlineData (MouseFlags.Button2Clicked)]
[InlineData (MouseFlags.Button3Clicked)]
[InlineData (MouseFlags.Button4Clicked)]
public void WantContinuousButtonPressed_True_Button_Clicked_Raises_Selecting (MouseFlags clicked)
{
var me = new MouseEventArgs ();
var view = new View
{
Width = 1,
Height = 1,
WantContinuousButtonPressed = true
};
var selectingCount = 0;
view.Selecting += (s, e) => selectingCount++;
me.Flags = clicked;
view.NewMouseEvent (me);
Assert.Equal (1, selectingCount);
view.Dispose ();
// Button1Pressed, Button1Released cause Application.Mouse.MouseGrabView to be set
Application.ResetState (true);
}
[Theory]
[InlineData (MouseFlags.Button1Pressed, MouseFlags.Button1Released)]
[InlineData (MouseFlags.Button2Pressed, MouseFlags.Button2Released)]
[InlineData (MouseFlags.Button3Pressed, MouseFlags.Button3Released)]
[InlineData (MouseFlags.Button4Pressed, MouseFlags.Button4Released)]
public void WantContinuousButtonPressed_True_And_WantMousePositionReports_True_Button_Press_Release_Clicks (MouseFlags pressed, MouseFlags released)
{
var me = new MouseEventArgs ();
var view = new View
{
Width = 1,
Height = 1,
WantContinuousButtonPressed = true,
WantMousePositionReports = true
};
// Setup components for mouse held down
var timed = new TimedEvents ();
var grab = new MouseGrabHandler ();
view.MouseHeldDown = new MouseHeldDown (view, timed, grab);
// Register callback for what to do when the mouse is held down
var clickedCount = 0;
view.MouseHeldDown.MouseIsHeldDownTick += (_, _) => clickedCount++;
// Mouse is currently not held down so should be no timers running
Assert.Empty(timed.Timeouts);
// When mouse is held down
me.Flags = pressed;
view.NewMouseEvent (me);
Assert.Equal (0, clickedCount);
me.Handled = false;
// A timer should begin
var t = Assert.Single (timed.Timeouts);
// Invoke the timer
t.Value.Callback.Invoke ();
// Event should have been raised
Assert.Equal (1, clickedCount);
Assert.NotEmpty(timed.Timeouts);
// When mouse is released
me.Flags = released;
view.NewMouseEvent (me);
// timer should stop
Assert.Empty (timed.Timeouts);
Assert.Equal (1, clickedCount);
view.Dispose ();
}
[Theory]
[InlineData (MouseFlags.Button1Pressed, MouseFlags.Button1Released, MouseFlags.Button1Clicked)]
[InlineData (MouseFlags.Button2Pressed, MouseFlags.Button2Released, MouseFlags.Button2Clicked)]
[InlineData (MouseFlags.Button3Pressed, MouseFlags.Button3Released, MouseFlags.Button3Clicked)]
[InlineData (MouseFlags.Button4Pressed, MouseFlags.Button4Released, MouseFlags.Button4Clicked)]
public void WantContinuousButtonPressed_True_And_WantMousePositionReports_True_Button_Press_Release_Clicks_Repeatedly (
MouseFlags pressed,
MouseFlags released,
MouseFlags clicked
)
{
var me = new MouseEventArgs ();
var view = new View
{
Width = 1,
Height = 1,
WantContinuousButtonPressed = true,
WantMousePositionReports = true
};
// Setup components for mouse held down
var timed = new TimedEvents ();
var grab = new MouseGrabHandler ();
view.MouseHeldDown = new MouseHeldDown (view, timed, grab);
// Register callback for what to do when the mouse is held down
var clickedCount = 0;
view.MouseHeldDown.MouseIsHeldDownTick += (_, _) => clickedCount++;
Assert.Empty (timed.Timeouts);
me.Flags = pressed;
view.NewMouseEvent (me);
Assert.Equal (0, clickedCount);
me.Handled = false;
Assert.NotEmpty(timed.Timeouts);
Assert.Single (timed.Timeouts).Value.Callback.Invoke ();
me.Flags = pressed;
view.NewMouseEvent (me);
Assert.Equal (1, clickedCount);
me.Handled = false;
Assert.NotEmpty (timed.Timeouts);
me.Flags = released;
view.NewMouseEvent (me);
Assert.Equal (1, clickedCount);
me.Handled = false;
Assert.Empty (timed.Timeouts);
me.Flags = clicked;
view.NewMouseEvent (me);
Assert.Equal (1, clickedCount);
view.Dispose ();
}
[Fact]
public void WantContinuousButtonPressed_True_And_WantMousePositionReports_True_Move_InViewport_OutOfViewport_Keeps_Counting ()
{
var me = new MouseEventArgs ();
var view = new View
{
Width = 1,
Height = 1,
WantContinuousButtonPressed = true,
WantMousePositionReports = true
};
// Setup components for mouse held down
var timed = new TimedEvents ();
var grab = new MouseGrabHandler ();
view.MouseHeldDown = new MouseHeldDown (view, timed, grab);
// Register callback for what to do when the mouse is held down
var clickedCount = 0;
view.MouseHeldDown.MouseIsHeldDownTick += (_, _) => clickedCount++;
// Start in Viewport
me.Flags = MouseFlags.Button1Pressed;
me.Position = me.Position with { X = 0 };
view.NewMouseEvent (me);
Assert.Equal (0, clickedCount);
me.Handled = false;
// Mouse is held down so timer should be ticking
Assert.NotEmpty (timed.Timeouts);
Assert.Equal (clickedCount,0);
// Don't wait, just force it to expire
Assert.Single (timed.Timeouts).Value.Callback.Invoke ();
Assert.Equal (clickedCount, 1);
// Move out of Viewport
me.Flags = MouseFlags.Button1Pressed;
me.Position = me.Position with { X = 1 };
view.NewMouseEvent (me);
Assert.Single (timed.Timeouts).Value.Callback.Invoke ();
Assert.Equal (clickedCount, 2);
me.Handled = false;
// Move into Viewport
me.Flags = MouseFlags.Button1Pressed;
me.Position = me.Position with { X = 0 };
view.NewMouseEvent (me);
Assert.NotEmpty (timed.Timeouts);
Assert.Equal (2, clickedCount);
me.Handled = false;
// Stay in Viewport
me.Flags = MouseFlags.Button1Pressed;
me.Position = me.Position with { X = 0 };
view.NewMouseEvent (me);
Assert.Single (timed.Timeouts).Value.Callback.Invoke ();
Assert.Equal (3, clickedCount);
me.Handled = false;
view.Dispose ();
}
//[Theory]
//[InlineData (true, MouseState.None, 0, 0, 0, 0)]
//[InlineData (true, MouseState.In, 0, 0, 0, 0)]
//[InlineData (true, MouseState.Pressed, 0, 0, 1, 0)]
//[InlineData (true, MouseState.PressedOutside, 0, 0, 0, 1)]
//public void MouseState_Button1_Pressed_Then_Released_Outside (bool inViewport, MouseState highlightFlags, int noneCount, int expectedInCount, int expectedPressedCount, int expectedPressedOutsideCount)
//{
// var testView = new MouseEventTestView
// {
// HighlightStates = highlightFlags
// };
// Assert.Equal (0, testView.MouseStateInCount);
// Assert.Equal (0, testView.MouseStatePressedCount);
// Assert.Equal (0, testView.MouseStatePressedOutsideCount);
// Assert.Equal (0, testView.MouseStateNoneCount);
// testView.NewMouseEvent (new () { Flags = MouseFlags.Button1Pressed, Position = new (inViewport ? 0 : 1, 0) });
// Assert.Equal (expectedInCount, testView.MouseStateInCount);
// Assert.Equal (expectedPressedCount, testView.MouseStatePressedCount);
// Assert.Equal (expectedPressedOutsideCount, testView.MouseStatePressedOutsideCount);
// Assert.Equal (noneCount, testView.MouseStateNoneCount);
// testView.NewMouseEvent (new () { Flags = MouseFlags.Button1Released, Position = new (inViewport ? 0 : 1, 0) });
// Assert.Equal (expectedInCount, testView.MouseStateInCount);
// Assert.Equal (expectedPressedCount, testView.MouseStatePressedCount);
// Assert.Equal (expectedPressedOutsideCount, testView.MouseStatePressedOutsideCount);
// Assert.Equal (noneCount, testView.MouseStateNoneCount);
// testView.Dispose ();
// // Button1Pressed, Button1Released cause Application.Mouse.MouseGrabView to be set
// Application.ResetState (true);
//}
// TODO: Add tests for each combination of HighlightFlags
[Theory]
[InlineData (0)]
[InlineData (1)]
[InlineData (10)]
public void MouseState_None_Button1_Pressed_Move_No_Changes (int x)
{
var testView = new MouseEventTestView
{
HighlightStates = MouseState.None
};
bool inViewport = testView.Viewport.Contains (x, 0);
// Start at 0,0 ; in viewport
testView.NewMouseEvent (new () { Flags = MouseFlags.Button1Pressed });
Assert.Equal (0, testView.MouseStateInCount);
Assert.Equal (0, testView.MouseStatePressedCount);
Assert.Equal (0, testView.MouseStatePressedOutsideCount);
Assert.Equal (0, testView.MouseStateNoneCount);
// Move to x,0
testView.NewMouseEvent (new () { Flags = MouseFlags.Button1Pressed, Position = new (x, 0) });
if (inViewport)
{
Assert.Equal (0, testView.MouseStateInCount);
Assert.Equal (0, testView.MouseStatePressedCount);
Assert.Equal (0, testView.MouseStatePressedOutsideCount);
Assert.Equal (0, testView.MouseStateNoneCount);
}
else
{
Assert.Equal (0, testView.MouseStateInCount);
Assert.Equal (0, testView.MouseStatePressedCount);
Assert.Equal (0, testView.MouseStatePressedOutsideCount);
Assert.Equal (0, testView.MouseStateNoneCount);
}
// Move backto 0,0 ; in viewport
testView.NewMouseEvent (new () { Flags = MouseFlags.Button1Pressed });
if (inViewport)
{
Assert.Equal (0, testView.MouseStateInCount);
Assert.Equal (0, testView.MouseStatePressedCount);
Assert.Equal (0, testView.MouseStatePressedOutsideCount);
Assert.Equal (0, testView.MouseStateNoneCount);
}
else
{
Assert.Equal (0, testView.MouseStateInCount);
Assert.Equal (0, testView.MouseStatePressedCount);
Assert.Equal (0, testView.MouseStatePressedOutsideCount);
Assert.Equal (0, testView.MouseStateNoneCount);
}
testView.Dispose ();
// Button1Pressed, Button1Released cause Application.Mouse.MouseGrabView to be set
Application.ResetState (true);
}
[Theory]
[InlineData (0)]
[InlineData (1)]
[InlineData (10)]
public void MouseState_Pressed_Button1_Pressed_Move_Keeps_Pressed (int x)
{
var testView = new MouseEventTestView
{
HighlightStates = MouseState.Pressed
};
bool inViewport = testView.Viewport.Contains (x, 0);
// Start at 0,0 ; in viewport
testView.NewMouseEvent (new () { Flags = MouseFlags.Button1Pressed });
Assert.Equal (0, testView.MouseStateInCount);
Assert.Equal (1, testView.MouseStatePressedCount);
Assert.Equal (0, testView.MouseStatePressedOutsideCount);
Assert.Equal (0, testView.MouseStateNoneCount);
// Move to x,0
testView.NewMouseEvent (new () { Flags = MouseFlags.Button1Pressed, Position = new (x, 0) });
if (inViewport)
{
Assert.Equal (0, testView.MouseStateInCount);
Assert.Equal (1, testView.MouseStatePressedCount);
Assert.Equal (0, testView.MouseStatePressedOutsideCount);
Assert.Equal (0, testView.MouseStateNoneCount);
}
else
{
Assert.Equal (0, testView.MouseStateInCount);
Assert.Equal (1, testView.MouseStatePressedCount);
Assert.Equal (0, testView.MouseStatePressedOutsideCount);
Assert.Equal (0, testView.MouseStateNoneCount);
}
// Move backto 0,0 ; in viewport
testView.NewMouseEvent (new () { Flags = MouseFlags.Button1Pressed });
if (inViewport)
{
Assert.Equal (0, testView.MouseStateInCount);
Assert.Equal (1, testView.MouseStatePressedCount);
Assert.Equal (0, testView.MouseStatePressedOutsideCount);
Assert.Equal (0, testView.MouseStateNoneCount);
}
else
{
Assert.Equal (0, testView.MouseStateInCount);
Assert.Equal (1, testView.MouseStatePressedCount);
Assert.Equal (0, testView.MouseStatePressedOutsideCount);
Assert.Equal (0, testView.MouseStateNoneCount);
}
testView.Dispose ();
// Button1Pressed, Button1Released cause Application.Mouse.MouseGrabView to be set
Application.ResetState (true);
}
[Theory]
[InlineData (0)]
[InlineData (1)]
[InlineData (10)]
public void MouseState_PressedOutside_Button1_Pressed_Move_Raises_PressedOutside (int x)
{
var testView = new MouseEventTestView
{
HighlightStates = MouseState.PressedOutside,
WantContinuousButtonPressed = false
};
bool inViewport = testView.Viewport.Contains (x, 0);
// Start at 0,0 ; in viewport
testView.NewMouseEvent (new () { Flags = MouseFlags.Button1Pressed });
Assert.Equal (0, testView.MouseStateInCount);
Assert.Equal (0, testView.MouseStatePressedCount);
Assert.Equal (0, testView.MouseStatePressedOutsideCount);
Assert.Equal (0, testView.MouseStateNoneCount);
// Move to x,0
testView.NewMouseEvent (new () { Flags = MouseFlags.Button1Pressed, Position = new (x, 0) });
if (inViewport)
{
Assert.Equal (0, testView.MouseStateInCount);
Assert.Equal (0, testView.MouseStatePressedCount);
Assert.Equal (0, testView.MouseStatePressedOutsideCount);
Assert.Equal (0, testView.MouseStateNoneCount);
}
else
{
Assert.Equal (0, testView.MouseStateInCount);
Assert.Equal (0, testView.MouseStatePressedCount);
Assert.Equal (1, testView.MouseStatePressedOutsideCount);
Assert.Equal (0, testView.MouseStateNoneCount);
}
// Move backto 0,0 ; in viewport
testView.NewMouseEvent (new () { Flags = MouseFlags.Button1Pressed });
if (inViewport)
{
Assert.Equal (0, testView.MouseStateInCount);
Assert.Equal (0, testView.MouseStatePressedCount);
Assert.Equal (0, testView.MouseStatePressedOutsideCount);
Assert.Equal (0, testView.MouseStateNoneCount);
}
else
{
Assert.Equal (0, testView.MouseStateInCount);
Assert.Equal (0, testView.MouseStatePressedCount);
Assert.Equal (1, testView.MouseStatePressedOutsideCount);
Assert.Equal (1, testView.MouseStateNoneCount);
}
testView.Dispose ();
// Button1Pressed, Button1Released cause Application.Mouse.MouseGrabView to be set
Application.ResetState (true);
}
[Theory]
[InlineData (0)]
[InlineData (1)]
[InlineData (10)]
public void MouseState_PressedOutside_Button1_Pressed_Move_Raises_PressedOutside_WantContinuousButtonPressed (int x)
{
var testView = new MouseEventTestView
{
HighlightStates = MouseState.PressedOutside,
WantContinuousButtonPressed = true
};
bool inViewport = testView.Viewport.Contains (x, 0);
// Start at 0,0 ; in viewport
testView.NewMouseEvent (new () { Flags = MouseFlags.Button1Pressed });
Assert.Equal (0, testView.MouseStateInCount);
Assert.Equal (0, testView.MouseStatePressedCount);
Assert.Equal (0, testView.MouseStatePressedOutsideCount);
Assert.Equal (0, testView.MouseStateNoneCount);
// Move to x,0
testView.NewMouseEvent (new () { Flags = MouseFlags.Button1Pressed, Position = new (x, 0) });
if (inViewport)
{
Assert.Equal (0, testView.MouseStateInCount);
Assert.Equal (0, testView.MouseStatePressedCount);
Assert.Equal (0, testView.MouseStatePressedOutsideCount);
Assert.Equal (0, testView.MouseStateNoneCount);
}
else
{
Assert.Equal (0, testView.MouseStateInCount);
Assert.Equal (0, testView.MouseStatePressedCount);
Assert.Equal (0, testView.MouseStatePressedOutsideCount);
Assert.Equal (0, testView.MouseStateNoneCount);
}
// Move backto 0,0 ; in viewport
testView.NewMouseEvent (new () { Flags = MouseFlags.Button1Pressed });
if (inViewport)
{
Assert.Equal (0, testView.MouseStateInCount);
Assert.Equal (0, testView.MouseStatePressedCount);
Assert.Equal (0, testView.MouseStatePressedOutsideCount);
Assert.Equal (0, testView.MouseStateNoneCount);
}
else
{
Assert.Equal (0, testView.MouseStateInCount);
Assert.Equal (0, testView.MouseStatePressedCount);
Assert.Equal (0, testView.MouseStatePressedOutsideCount);
Assert.Equal (0, testView.MouseStateNoneCount);
}
testView.Dispose ();
// Button1Pressed, Button1Released cause Application.Mouse.MouseGrabView to be set
Application.ResetState (true);
}
private class MouseEventTestView : View
{
public int MouseEnterCount { get; private set; }
public int MouseLeaveCount { get; private set; }
public int MouseStatePressedOutsideCount { get; private set; }
public int MouseStateInCount { get; private set; }
public int MouseStatePressedCount { get; private set; }
public int MouseStateNoneCount { get; private set; }
public MouseEventTestView ()
{
Height = 1;
Width = 1;
CanFocus = true;
Id = "mouseEventTestView";
MouseLeave += (s, e) => { MouseEnterCount++; };
MouseEnter += (s, e) => { MouseLeaveCount++; };
}
/// <inheritdoc/>
protected override void OnMouseStateChanged (EventArgs<MouseState> args)
{
switch (args.Value)
{
case MouseState.None:
MouseStateNoneCount++;
break;
case MouseState.In:
MouseStateInCount++;
break;
case MouseState.Pressed:
MouseStatePressedCount++;
break;
case MouseState.PressedOutside:
MouseStatePressedOutsideCount++;
break;
}
base.OnMouseStateChanged (args);
}
}
}