diff --git a/Terminal.Gui/Views/Autocomplete/PopupAutocomplete.cs b/Terminal.Gui/Views/Autocomplete/PopupAutocomplete.cs index 78487276d7..d64d28315e 100644 --- a/Terminal.Gui/Views/Autocomplete/PopupAutocomplete.cs +++ b/Terminal.Gui/Views/Autocomplete/PopupAutocomplete.cs @@ -75,6 +75,17 @@ public override View HostControl } } + /// + public override bool Visible + { + get; + set + { + field = value; + _popup.Visible = value; + } + } + /// public override void EnsureSelectedIdxIsValid () { @@ -388,7 +399,6 @@ public override void RenderOverlay (Point renderAt) ); } - _popup.Visible = true; _popup.Move (0, 0); for (var i = 0; i < toRender.Length; i++) @@ -426,7 +436,6 @@ protected void Close () _closed = true; //RemovePopupFromTop (); - _popup.Visible = false; HostControl?.SetNeedsDraw (); } @@ -514,7 +523,6 @@ protected bool ReopenSuggestions () { Visible = true; _closed = false; - _popup.Visible = true; HostControl?.SetNeedsDraw (); return true; diff --git a/Terminal.Gui/Views/TextInput/TextView/TextView.Mouse.cs b/Terminal.Gui/Views/TextInput/TextView/TextView.Mouse.cs index 239a433513..e1fe5aa46a 100644 --- a/Terminal.Gui/Views/TextInput/TextView/TextView.Mouse.cs +++ b/Terminal.Gui/Views/TextInput/TextView/TextView.Mouse.cs @@ -224,7 +224,7 @@ private void ProcessMouseClick (Mouse mouse, out List line) int desiredInsertionY = Math.Clamp (Viewport.Y + p.Y, 0, _model.Count); int movementY = desiredInsertionY - _lastMouseInsertionPointY; - if (Viewport.Y + p.Y > _model.Count || (IsSelecting && p.Y >= Math.Max (Viewport.Height - 1, 0))) + if (Viewport.Y + p.Y >= _model.Count || (IsSelecting && p.Y >= Math.Max (Viewport.Height - 1, 0))) { CurrentRow = _model.Count - 1; } diff --git a/Tests/UnitTestsParallelizable/Views/TextView.AutocompleteTests.cs b/Tests/UnitTestsParallelizable/Views/TextView.AutocompleteTests.cs index a0aae1fc26..ee6ca4ad2f 100644 --- a/Tests/UnitTestsParallelizable/Views/TextView.AutocompleteTests.cs +++ b/Tests/UnitTestsParallelizable/Views/TextView.AutocompleteTests.cs @@ -352,4 +352,35 @@ void DoTest (object? _, EventArgs args) } } } + + [Fact] + public void Autocomplete_Popup_Sets_Visible_To_False_When_Clicked_Outside_Of_Popup () + { + TextView tv = new () { Width = Dim.Fill (), Height = 10, Text = " some text" }; + using IApplication testApp = RunTestApplication (50, 15, DoTest, false, output); + + return; + + void DoTest (object? _, EventArgs args) + { + IApplication app = args.Value!; + + (app.TopRunnable as View)!.Add (tv); + + SingleWordSuggestionGenerator g = (SingleWordSuggestionGenerator)tv.Autocomplete.SuggestionGenerator; + g.AllSuggestions = ["item"]; + + tv.SetFocus (); + + app.InjectKey (Key.I); + Assert.Equal ("i some text", tv.Text); + Assert.True (tv.Autocomplete.Visible); + + // Click outside of popup + app.InjectMouse (new Mouse { ScreenPosition = new Point (5, 1), Flags = MouseFlags.LeftButtonClicked }); + + Assert.False (tv.Autocomplete.Visible); + app.RequestStop (); + } + } } diff --git a/Tests/UnitTestsParallelizable/Views/TextViewTests.cs b/Tests/UnitTestsParallelizable/Views/TextViewTests.cs index 7f3b818a4f..6f01192296 100644 --- a/Tests/UnitTestsParallelizable/Views/TextViewTests.cs +++ b/Tests/UnitTestsParallelizable/Views/TextViewTests.cs @@ -3613,6 +3613,45 @@ public void Mouse_Click_At_Position_GreaterThanZero_On_Empty_TextView_Should_Set Assert.Equal (new Point (0, 0), tv.Viewport.Location); } + [Fact] + public void Mouse_Click_At_Position_GreaterOrEqual_To_Lines_Count_Should_Set_InsertionPoint_To_Last_Line () + { + // Create a TextView with 3 lines of text + TextView tv = new () { Width = 6, Height = 5 }; + tv.Text = "Line1\nLine2\nLine3"; + tv.BeginInit (); + tv.EndInit (); + + // Verify initial state + Assert.False (tv.WordWrap); + Assert.Equal (3, tv.Lines); + Assert.Equal (new Point (0, 0), tv.InsertionPoint); + Assert.Equal (new Point (0, 0), tv.Viewport.Location); + + // Simulate mouse click at Y position greater than or equal to LinesCount + Mouse ev = new () { Position = new Point (0, 3), Flags = MouseFlags.LeftButtonClicked }; + tv.NewMouseEvent (ev); + + // Verify InsertionPoint is set to the last line + Assert.Equal (new Point (0, 2), tv.InsertionPoint); + + // Now test with WordWrap enabled + tv.WordWrap = true; + + // Verify initial state with WordWrap enabled + Assert.True (tv.WordWrap); + Assert.Equal (3, tv.Lines); + Assert.Equal (new Point (0, 0), tv.InsertionPoint); + Assert.Equal (new Point (0, 0), tv.Viewport.Location); + + // Simulate mouse click at Y position greater than or equal to LinesCount + ev = new Mouse { Position = new Point (0, 3), Flags = MouseFlags.LeftButtonClicked }; + tv.NewMouseEvent (ev); + + // Verify InsertionPoint is set to the last line + Assert.Equal (new Point (0, 2), tv.InsertionPoint); + } + [Fact] public void MoveEnd_AdjustsViewportToShowInsertionPoint_When_InsertionPointIsBeyondViewport () {