Skip to content

Commit 33d95c6

Browse files
markl65536Markusmaxkatz6Gillibald
authored
Discard additional lines upon inserting when AcceptsReturn=false (#14173)
* Discard additional lines upon inserting when AcceptReturn=false * Use LineBreakEnumerator for detecting line breaks * Remove unused member Co-authored-by: Max Katz <[email protected]> * Use Grapheme enumerator --------- Co-authored-by: Markus <[email protected]> Co-authored-by: Max Katz <[email protected]> Co-authored-by: Benedikt Stebner <[email protected]>
1 parent 06f88f6 commit 33d95c6

File tree

2 files changed

+65
-7
lines changed

2 files changed

+65
-7
lines changed

src/Avalonia.Controls/TextBox.cs

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
using Avalonia.Controls.Metadata;
1717
using Avalonia.Media.TextFormatting;
1818
using Avalonia.Automation.Peers;
19+
using Avalonia.Media.TextFormatting.Unicode;
1920
using Avalonia.Threading;
2021

2122
namespace Avalonia.Controls
@@ -837,7 +838,7 @@ protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
837838

838839
_scrollViewer = e.NameScope.Find<ScrollViewer>("PART_ScrollViewer");
839840

840-
if(_scrollViewer != null)
841+
if (_scrollViewer != null)
841842
{
842843
_scrollViewer.ScrollChanged += ScrollViewer_ScrollChanged;
843844
}
@@ -886,9 +887,9 @@ protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e
886887

887888
private void PresenterPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
888889
{
889-
if(e.Property == TextPresenter.PreeditTextProperty)
890+
if (e.Property == TextPresenter.PreeditTextProperty)
890891
{
891-
if(string.IsNullOrEmpty(e.OldValue as string) && !string.IsNullOrEmpty(e.NewValue as string))
892+
if (string.IsNullOrEmpty(e.OldValue as string) && !string.IsNullOrEmpty(e.NewValue as string))
892893
{
893894
PseudoClasses.Set(":empty", false);
894895

@@ -1013,7 +1014,7 @@ private void HandleTextInput(string? input)
10131014
return;
10141015
}
10151016

1016-
input = RemoveInvalidCharacters(input);
1017+
input = SanitizeInputText(input);
10171018

10181019
if (string.IsNullOrEmpty(input))
10191020
{
@@ -1066,11 +1067,30 @@ private void HandleTextInput(string? input)
10661067
}
10671068
}
10681069

1069-
private string? RemoveInvalidCharacters(string? text)
1070+
private string? SanitizeInputText(string? text)
10701071
{
10711072
if (text is null)
10721073
return null;
10731074

1075+
if (!AcceptsReturn)
1076+
{
1077+
var lineBreakStart = 0;
1078+
var graphemeEnumerator = new GraphemeEnumerator(text.AsSpan());
1079+
1080+
while (graphemeEnumerator.MoveNext(out var grapheme))
1081+
{
1082+
if (grapheme.FirstCodepoint.IsBreakChar)
1083+
{
1084+
break;
1085+
}
1086+
1087+
lineBreakStart += grapheme.Length;
1088+
}
1089+
1090+
// All lines except the first one are discarded when TextBox does not accept Return key
1091+
text = text.Substring(0, lineBreakStart);
1092+
}
1093+
10741094
for (var i = 0; i < invalidCharacters.Length; i++)
10751095
{
10761096
text = text.Replace(invalidCharacters[i], string.Empty);
@@ -1757,7 +1777,7 @@ protected override void OnPointerReleased(PointerReleasedEventArgs e)
17571777
SetCurrentValue(SelectionEndProperty, caretIndex);
17581778
}
17591779

1760-
if(SelectionStart != SelectionEnd)
1780+
if (SelectionStart != SelectionEnd)
17611781
{
17621782
_presenter.TextSelectionHandleCanvas?.ShowContextMenu();
17631783
}
@@ -2228,7 +2248,7 @@ void UndoRedoHelper<UndoRedoState>.IUndoRedoHost.OnRedoStackChanged()
22282248

22292249
protected override Size MeasureOverride(Size availableSize)
22302250
{
2231-
if(_scrollViewer != null)
2251+
if (_scrollViewer != null)
22322252
{
22332253
var maxHeight = double.PositiveInfinity;
22342254

tests/Avalonia.Controls.UnitTests/TextBoxTests.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -949,6 +949,44 @@ public void Entering_Text_With_SelectedText_Should_Fire_Single_Text_Changed_Noti
949949
}
950950
}
951951

952+
[Fact]
953+
public void Insert_Multiline_Text_Should_Accept_Extra_Lines_When_AcceptsReturn_Is_True()
954+
{
955+
using (UnitTestApplication.Start(Services))
956+
{
957+
var target = new TextBox
958+
{
959+
AcceptsReturn = true
960+
};
961+
962+
RaiseTextEvent(target, $"123 {Environment.NewLine}456");
963+
964+
Assert.Equal($"123 {Environment.NewLine}456", target.Text);
965+
}
966+
}
967+
968+
[Fact]
969+
public void Insert_Multiline_Text_Should_Discard_Extra_Lines_When_AcceptsReturn_Is_False()
970+
{
971+
using (UnitTestApplication.Start(Services))
972+
{
973+
var target = new TextBox
974+
{
975+
AcceptsReturn = false
976+
};
977+
978+
RaiseTextEvent(target, $"123 {"\r"}456");
979+
980+
Assert.Equal("123 ", target.Text);
981+
982+
target.Text = "";
983+
984+
RaiseTextEvent(target, $"123 {"\r\n"}456");
985+
986+
Assert.Equal("123 ", target.Text);
987+
}
988+
}
989+
952990
[Fact]
953991
public void Should_Fullfill_MaxLines_Contraint()
954992
{

0 commit comments

Comments
 (0)