|
|
@ -174,6 +174,10 @@ namespace Avalonia.Controls |
|
|
private string _newLine = Environment.NewLine; |
|
|
private string _newLine = Environment.NewLine; |
|
|
private static readonly string[] invalidCharacters = new String[1] { "\u007f" }; |
|
|
private static readonly string[] invalidCharacters = new String[1] { "\u007f" }; |
|
|
|
|
|
|
|
|
|
|
|
private int _selectedTextChangesMadeSinceLastUndoSnapshot; |
|
|
|
|
|
private bool _hasDoneSnapshotOnce; |
|
|
|
|
|
private const int _maxCharsBeforeUndoSnapshot = 7; |
|
|
|
|
|
|
|
|
static TextBox() |
|
|
static TextBox() |
|
|
{ |
|
|
{ |
|
|
FocusableProperty.OverrideDefaultValue(typeof(TextBox), true); |
|
|
FocusableProperty.OverrideDefaultValue(typeof(TextBox), true); |
|
|
@ -202,7 +206,8 @@ namespace Avalonia.Controls |
|
|
horizontalScrollBarVisibility, |
|
|
horizontalScrollBarVisibility, |
|
|
BindingPriority.Style); |
|
|
BindingPriority.Style); |
|
|
_undoRedoHelper = new UndoRedoHelper<UndoRedoState>(this); |
|
|
_undoRedoHelper = new UndoRedoHelper<UndoRedoState>(this); |
|
|
|
|
|
_selectedTextChangesMadeSinceLastUndoSnapshot = 0; |
|
|
|
|
|
_hasDoneSnapshotOnce = false; |
|
|
UpdatePseudoclasses(); |
|
|
UpdatePseudoclasses(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -331,6 +336,7 @@ namespace Avalonia.Controls |
|
|
if (SetAndRaise(TextProperty, ref _text, value) && IsUndoEnabled && !_isUndoingRedoing) |
|
|
if (SetAndRaise(TextProperty, ref _text, value) && IsUndoEnabled && !_isUndoingRedoing) |
|
|
{ |
|
|
{ |
|
|
_undoRedoHelper.Clear(); |
|
|
_undoRedoHelper.Clear(); |
|
|
|
|
|
SnapshotUndoRedo(); // so we always have an initial state
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
@ -341,7 +347,6 @@ namespace Avalonia.Controls |
|
|
get { return GetSelection(); } |
|
|
get { return GetSelection(); } |
|
|
set |
|
|
set |
|
|
{ |
|
|
{ |
|
|
SnapshotUndoRedo(); |
|
|
|
|
|
if (string.IsNullOrEmpty(value)) |
|
|
if (string.IsNullOrEmpty(value)) |
|
|
{ |
|
|
{ |
|
|
DeleteSelection(); |
|
|
DeleteSelection(); |
|
|
@ -350,7 +355,6 @@ namespace Avalonia.Controls |
|
|
{ |
|
|
{ |
|
|
HandleTextInput(value); |
|
|
HandleTextInput(value); |
|
|
} |
|
|
} |
|
|
SnapshotUndoRedo(); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -485,6 +489,8 @@ namespace Avalonia.Controls |
|
|
// https://docs.microsoft.com/en-us/dotnet/api/system.windows.controls.primitives.textboxbase.isundoenabled:
|
|
|
// https://docs.microsoft.com/en-us/dotnet/api/system.windows.controls.primitives.textboxbase.isundoenabled:
|
|
|
// "Setting UndoLimit clears the undo queue."
|
|
|
// "Setting UndoLimit clears the undo queue."
|
|
|
_undoRedoHelper.Clear(); |
|
|
_undoRedoHelper.Clear(); |
|
|
|
|
|
_selectedTextChangesMadeSinceLastUndoSnapshot = 0; |
|
|
|
|
|
_hasDoneSnapshotOnce = false; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -515,6 +521,8 @@ namespace Avalonia.Controls |
|
|
// Therefore, if you disable undo and then re-enable it, undo commands still do not work
|
|
|
// Therefore, if you disable undo and then re-enable it, undo commands still do not work
|
|
|
// because the undo stack was emptied when you disabled undo."
|
|
|
// because the undo stack was emptied when you disabled undo."
|
|
|
_undoRedoHelper.Clear(); |
|
|
_undoRedoHelper.Clear(); |
|
|
|
|
|
_selectedTextChangesMadeSinceLastUndoSnapshot = 0; |
|
|
|
|
|
_hasDoneSnapshotOnce = false; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -584,6 +592,8 @@ namespace Avalonia.Controls |
|
|
{ |
|
|
{ |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
_selectedTextChangesMadeSinceLastUndoSnapshot++; |
|
|
|
|
|
SnapshotUndoRedo(ignoreChangeCount: false); |
|
|
|
|
|
|
|
|
string text = Text ?? string.Empty; |
|
|
string text = Text ?? string.Empty; |
|
|
int caretIndex = CaretIndex; |
|
|
int caretIndex = CaretIndex; |
|
|
@ -696,6 +706,7 @@ namespace Avalonia.Controls |
|
|
{ |
|
|
{ |
|
|
try |
|
|
try |
|
|
{ |
|
|
{ |
|
|
|
|
|
SnapshotUndoRedo(); |
|
|
_isUndoingRedoing = true; |
|
|
_isUndoingRedoing = true; |
|
|
_undoRedoHelper.Undo(); |
|
|
_undoRedoHelper.Undo(); |
|
|
} |
|
|
} |
|
|
@ -830,7 +841,6 @@ namespace Avalonia.Controls |
|
|
CaretIndex -= removedCharacters; |
|
|
CaretIndex -= removedCharacters; |
|
|
ClearSelection(); |
|
|
ClearSelection(); |
|
|
} |
|
|
} |
|
|
SnapshotUndoRedo(); |
|
|
|
|
|
|
|
|
|
|
|
handled = true; |
|
|
handled = true; |
|
|
break; |
|
|
break; |
|
|
@ -858,7 +868,6 @@ namespace Avalonia.Controls |
|
|
SetTextInternal(text.Substring(0, caretIndex) + |
|
|
SetTextInternal(text.Substring(0, caretIndex) + |
|
|
text.Substring(caretIndex + removedCharacters)); |
|
|
text.Substring(caretIndex + removedCharacters)); |
|
|
} |
|
|
} |
|
|
SnapshotUndoRedo(); |
|
|
|
|
|
|
|
|
|
|
|
handled = true; |
|
|
handled = true; |
|
|
break; |
|
|
break; |
|
|
@ -868,7 +877,6 @@ namespace Avalonia.Controls |
|
|
{ |
|
|
{ |
|
|
SnapshotUndoRedo(); |
|
|
SnapshotUndoRedo(); |
|
|
HandleTextInput(NewLine); |
|
|
HandleTextInput(NewLine); |
|
|
SnapshotUndoRedo(); |
|
|
|
|
|
handled = true; |
|
|
handled = true; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -879,7 +887,6 @@ namespace Avalonia.Controls |
|
|
{ |
|
|
{ |
|
|
SnapshotUndoRedo(); |
|
|
SnapshotUndoRedo(); |
|
|
HandleTextInput("\t"); |
|
|
HandleTextInput("\t"); |
|
|
SnapshotUndoRedo(); |
|
|
|
|
|
handled = true; |
|
|
handled = true; |
|
|
} |
|
|
} |
|
|
else |
|
|
else |
|
|
@ -889,6 +896,10 @@ namespace Avalonia.Controls |
|
|
|
|
|
|
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
case Key.Space: |
|
|
|
|
|
SnapshotUndoRedo(); // always snapshot in between words
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
default: |
|
|
default: |
|
|
handled = false; |
|
|
handled = false; |
|
|
break; |
|
|
break; |
|
|
@ -1306,11 +1317,19 @@ namespace Avalonia.Controls |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private void SnapshotUndoRedo() |
|
|
private void SnapshotUndoRedo(bool ignoreChangeCount = true) |
|
|
{ |
|
|
{ |
|
|
if (IsUndoEnabled) |
|
|
if (IsUndoEnabled) |
|
|
|
|
|
{ |
|
|
|
|
|
if (ignoreChangeCount || |
|
|
|
|
|
!_hasDoneSnapshotOnce || |
|
|
|
|
|
(!ignoreChangeCount && |
|
|
|
|
|
_selectedTextChangesMadeSinceLastUndoSnapshot >= _maxCharsBeforeUndoSnapshot)) |
|
|
{ |
|
|
{ |
|
|
_undoRedoHelper.Snapshot(); |
|
|
_undoRedoHelper.Snapshot(); |
|
|
|
|
|
_selectedTextChangesMadeSinceLastUndoSnapshot = 0; |
|
|
|
|
|
_hasDoneSnapshotOnce = true; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|