Browse Source

Fix: TextBox having selection and pressing up / down arrows (#18385)

pull/18405/head
Rastislav Svoboda 11 months ago
committed by GitHub
parent
commit
6e1cab99f6
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 31
      src/Avalonia.Controls/TextBox.cs
  2. 174
      tests/Avalonia.Controls.UnitTests/TextBoxTests.cs

31
src/Avalonia.Controls/TextBox.cs

@ -1467,6 +1467,11 @@ namespace Avalonia.Controls
{
selection = DetectSelection();
if (!selection && SelectionStart != SelectionEnd)
{
ClearSelectionAndMoveCaretToTextPosition(LogicalDirection.Backward);
}
_presenter.MoveCaretVertical(LogicalDirection.Backward);
if (caretIndex != _presenter.CaretIndex)
@ -1489,6 +1494,11 @@ namespace Avalonia.Controls
{
selection = DetectSelection();
if (!selection && SelectionStart != SelectionEnd)
{
ClearSelectionAndMoveCaretToTextPosition(LogicalDirection.Forward);
}
_presenter.MoveCaretVertical();
if (caretIndex != _presenter.CaretIndex)
@ -1983,13 +1993,9 @@ namespace Avalonia.Controls
{
if (selectionStart != selectionEnd)
{
// clear the selection and move to the appropriate side of previous selection
var newPosition = direction > 0 ?
Math.Max(selectionStart, selectionEnd) :
Math.Min(selectionStart, selectionEnd);
SetCurrentValue(SelectionStartProperty, newPosition);
SetCurrentValue(SelectionEndProperty, newPosition);
_presenter.MoveCaretToTextPosition(newPosition);
ClearSelectionAndMoveCaretToTextPosition(direction > 0 ?
LogicalDirection.Forward :
LogicalDirection.Backward);
}
else
{
@ -2100,6 +2106,17 @@ namespace Avalonia.Controls
_scrollViewer?.PageDown();
}
private void ClearSelectionAndMoveCaretToTextPosition(LogicalDirection direction)
{
var newPosition = direction == LogicalDirection.Forward ?
Math.Max(SelectionStart, SelectionEnd) :
Math.Min(SelectionStart, SelectionEnd);
SetCurrentValue(SelectionStartProperty, newPosition);
SetCurrentValue(SelectionEndProperty, newPosition);
// move caret to appropriate side of previous selection
_presenter?.MoveCaretToTextPosition(newPosition);
}
/// <summary>
/// Scroll the <see cref="TextBox"/> to the specified line index.
/// </summary>

174
tests/Avalonia.Controls.UnitTests/TextBoxTests.cs

@ -1540,6 +1540,7 @@ namespace Avalonia.Controls.UnitTests
[InlineData(0,4)]
[InlineData(2,6)]
[InlineData(0,6)]
[InlineData(3,4)]
public void When_Selection_From_Left_To_Right_Pressing_Right_Should_Remove_Selection_Moving_Caret_To_End_Of_Previous_Selection(int selectionStart, int selectionEnd)
{
using (UnitTestApplication.Start(Services))
@ -1568,6 +1569,7 @@ namespace Avalonia.Controls.UnitTests
[InlineData(0,4)]
[InlineData(2,6)]
[InlineData(0,6)]
[InlineData(3,4)]
public void When_Selection_From_Left_To_Right_Pressing_Left_Should_Remove_Selection_Moving_Caret_To_Start_Of_Previous_Selection(int selectionStart, int selectionEnd)
{
using (UnitTestApplication.Start(Services))
@ -1596,6 +1598,7 @@ namespace Avalonia.Controls.UnitTests
[InlineData(4,0)]
[InlineData(6,2)]
[InlineData(6,0)]
[InlineData(4,3)]
public void When_Selection_From_Right_To_Left_Pressing_Right_Should_Remove_Selection_Moving_Caret_To_Start_Of_Previous_Selection(int selectionStart, int selectionEnd)
{
using (UnitTestApplication.Start(Services))
@ -1624,6 +1627,7 @@ namespace Avalonia.Controls.UnitTests
[InlineData(4,0)]
[InlineData(6,2)]
[InlineData(6,0)]
[InlineData(4,3)]
public void When_Selection_From_Right_To_Left_Pressing_Left_Should_Remove_Selection_Moving_Caret_To_End_Of_Previous_Selection(int selectionStart, int selectionEnd)
{
using (UnitTestApplication.Start(Services))
@ -1701,6 +1705,176 @@ namespace Avalonia.Controls.UnitTests
}
}
[Theory]
[InlineData(2,4)]
[InlineData(0,4)]
[InlineData(2,6)]
[InlineData(0,6)]
[InlineData(3,4)]
public void When_Selection_From_Left_To_Right_Pressing_Up_Should_Remove_Selection_Moving_Caret_To_Start_Of_Previous_Selection(int selectionStart, int selectionEnd)
{
using (UnitTestApplication.Start(Services))
{
var tb = new TextBox
{
Template = CreateTemplate(),
Text = "ABCDEF"
};
tb.Measure(Size.Infinity);
tb.CaretIndex = selectionStart;
tb.SelectionStart = selectionStart;
tb.SelectionEnd = selectionEnd;
RaiseKeyEvent(tb, Key.Up, KeyModifiers.None);
Assert.Equal(selectionStart, tb.SelectionStart);
Assert.Equal(selectionStart, tb.SelectionEnd);
Assert.Equal(selectionStart, tb.CaretIndex);
}
}
[Theory]
[InlineData(4,2)]
[InlineData(4,0)]
[InlineData(6,2)]
[InlineData(6,0)]
[InlineData(4,3)]
public void When_Selection_From_Right_To_Left_Pressing_Up_Should_Remove_Selection_Moving_Caret_To_End_Of_Previous_Selection(int selectionStart, int selectionEnd)
{
using (UnitTestApplication.Start(Services))
{
var tb = new TextBox
{
Template = CreateTemplate(),
Text = "ABCDEF"
};
tb.Measure(Size.Infinity);
tb.CaretIndex = selectionStart;
tb.SelectionStart = selectionStart;
tb.SelectionEnd = selectionEnd;
RaiseKeyEvent(tb, Key.Up, KeyModifiers.None);
Assert.Equal(selectionEnd, tb.SelectionStart);
Assert.Equal(selectionEnd, tb.SelectionEnd);
Assert.Equal(selectionEnd, tb.CaretIndex);
}
}
[Theory]
[InlineData(0)]
[InlineData(2)]
[InlineData(4)]
[InlineData(6)]
public void When_Select_All_From_Position_Up_Should_Remove_Selection_Moving_Caret_To_Start(int caretIndex)
{
using (UnitTestApplication.Start(Services))
{
var tb = new TextBox
{
Template = CreateTemplate(),
Text = "ABCDEF"
};
tb.Measure(Size.Infinity);
tb.CaretIndex = caretIndex;
RaiseKeyEvent(tb, Key.A, KeyModifiers.Control);
RaiseKeyEvent(tb, Key.Up, KeyModifiers.None);
Assert.Equal(0, tb.SelectionStart);
Assert.Equal(0, tb.SelectionEnd);
Assert.Equal(0, tb.CaretIndex);
}
}
[Theory]
[InlineData(2,4)]
[InlineData(0,4)]
[InlineData(2,6)]
[InlineData(0,6)]
[InlineData(3,4)]
public void When_Selection_From_Left_To_Right_Pressing_Down_Should_Remove_Selection_Moving_Caret_To_End_Of_Previous_Selection(int selectionStart, int selectionEnd)
{
using (UnitTestApplication.Start(Services))
{
var tb = new TextBox
{
Template = CreateTemplate(),
Text = "ABCDEF"
};
tb.Measure(Size.Infinity);
tb.CaretIndex = selectionStart;
tb.SelectionStart = selectionStart;
tb.SelectionEnd = selectionEnd;
RaiseKeyEvent(tb, Key.Down, KeyModifiers.None);
Assert.Equal(selectionEnd, tb.SelectionStart);
Assert.Equal(selectionEnd, tb.SelectionEnd);
Assert.Equal(selectionEnd, tb.CaretIndex);
}
}
[Theory]
[InlineData(4,2)]
[InlineData(4,0)]
[InlineData(6,2)]
[InlineData(6,0)]
[InlineData(4,3)]
public void When_Selection_From_Right_To_Left_Pressing_Down_Should_Remove_Selection_Moving_Caret_To_Start_Of_Previous_Selection(int selectionStart, int selectionEnd)
{
using (UnitTestApplication.Start(Services))
{
var tb = new TextBox
{
Template = CreateTemplate(),
Text = "ABCDEF"
};
tb.Measure(Size.Infinity);
tb.CaretIndex = selectionStart;
tb.SelectionStart = selectionStart;
tb.SelectionEnd = selectionEnd;
RaiseKeyEvent(tb, Key.Down, KeyModifiers.None);
Assert.Equal(selectionStart, tb.SelectionStart);
Assert.Equal(selectionStart, tb.SelectionEnd);
Assert.Equal(selectionStart, tb.CaretIndex);
}
}
[Theory]
[InlineData(0)]
[InlineData(2)]
[InlineData(4)]
[InlineData(6)]
public void When_Select_All_From_Position_Down_Should_Remove_Selection_Moving_Caret_To_End(int caretIndex)
{
using (UnitTestApplication.Start(Services))
{
var tb = new TextBox
{
Template = CreateTemplate(),
Text = "ABCDEF"
};
tb.Measure(Size.Infinity);
tb.CaretIndex = caretIndex;
RaiseKeyEvent(tb, Key.A, KeyModifiers.Control);
RaiseKeyEvent(tb, Key.Down, KeyModifiers.None);
Assert.Equal(tb.Text.Length, tb.SelectionStart);
Assert.Equal(tb.Text.Length, tb.SelectionEnd);
Assert.Equal(tb.Text.Length, tb.CaretIndex);
}
}
[Fact]
public void TextBox_In_AdornerLayer_Will_Not_Cause_Collection_Modified_In_VisualLayerManager_Measure()
{

Loading…
Cancel
Save