From c261a60018b018058f5171f9c017b497c2eb9c6c Mon Sep 17 00:00:00 2001 From: Magnus Lindhe Date: Tue, 24 Oct 2023 18:33:11 +0200 Subject: [PATCH] Add TextBox.ScrollToLine (#13274) * Add TextBox.ScrollToLine #3036 * Test data in arabic for RTL testing --- src/Avalonia.Controls/TextBox.cs | 22 ++++++++++ .../TextBoxTests.cs | 41 +++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index e246d48831..5d2b7bcb53 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -1877,6 +1877,28 @@ namespace Avalonia.Controls _scrollViewer?.PageDown(); } + /// + /// Scroll the to the specified line index. + /// + /// The line index to scroll to. + /// is less than zero. -or - is larger than or equal to the line count. + public void ScrollToLine(int lineIndex) + { + if (_presenter is null) + { + return; + } + + if (lineIndex < 0 || lineIndex >= _presenter.TextLayout.TextLines.Count) + { + throw new ArgumentOutOfRangeException(nameof(lineIndex)); + } + + var textLine = _presenter.TextLayout.TextLines[lineIndex]; + _presenter.MoveCaretToTextPosition(textLine.FirstTextSourceIndex); + + } + /// /// Select all text in the TextBox /// diff --git a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs index 3c7fb6f9c0..1ee154c44a 100644 --- a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs @@ -1182,6 +1182,47 @@ namespace Avalonia.Controls.UnitTests } } + [Theory] + [InlineData("A\nBB\nCCC\nDDDD", 0, 0)] + [InlineData("A\nBB\nCCC\nDDDD", 1, 2)] + [InlineData("A\nBB\nCCC\nDDDD", 2, 5)] + [InlineData("A\nBB\nCCC\nDDDD", 3, 9)] + [InlineData("واحد\nاثنين\nثلاثة\nأربعة", 0, 0)] + [InlineData("واحد\nاثنين\nثلاثة\nأربعة", 1, 5)] + [InlineData("واحد\nاثنين\nثلاثة\nأربعة", 2, 11)] + [InlineData("واحد\nاثنين\nثلاثة\nأربعة", 3, 17)] + public void Should_Scroll_Caret_To_Line(string text, int targetLineIndex, int expectedCaretIndex) + { + using (UnitTestApplication.Start(Services)) + { + var tb = new TextBox + { + Template = CreateTemplate(), + Text = text + }; + tb.ApplyTemplate(); + tb.ScrollToLine(targetLineIndex); + Assert.Equal(expectedCaretIndex, tb.CaretIndex); + } + } + + [Fact] + public void Should_Throw_ArgumentOutOfRange() + { + using (UnitTestApplication.Start(Services)) + { + var tb = new TextBox + { + Template = CreateTemplate(), + Text = string.Empty + }; + tb.ApplyTemplate(); + + Assert.Throws(() => tb.ScrollToLine(-1)); + Assert.Throws(() => tb.ScrollToLine(1)); + } + } + private static TestServices FocusServices => TestServices.MockThreadingInterface.With( focusManager: new FocusManager(), keyboardDevice: () => new KeyboardDevice(),