|
|
|
@ -119,9 +119,9 @@ namespace Avalonia.Controls |
|
|
|
AvaloniaProperty.Register<TextBox, bool>(nameof(RevealPassword)); |
|
|
|
|
|
|
|
public static readonly DirectProperty<TextBox, bool> CanCutProperty = |
|
|
|
AvaloniaProperty.RegisterDirect<TextBox, bool>( |
|
|
|
nameof(CanCut), |
|
|
|
o => o.CanCut); |
|
|
|
AvaloniaProperty.RegisterDirect<TextBox, bool>( |
|
|
|
nameof(CanCut), |
|
|
|
o => o.CanCut); |
|
|
|
|
|
|
|
public static readonly DirectProperty<TextBox, bool> CanCopyProperty = |
|
|
|
AvaloniaProperty.RegisterDirect<TextBox, bool>( |
|
|
|
@ -129,9 +129,21 @@ namespace Avalonia.Controls |
|
|
|
o => o.CanCopy); |
|
|
|
|
|
|
|
public static readonly DirectProperty<TextBox, bool> CanPasteProperty = |
|
|
|
AvaloniaProperty.RegisterDirect<TextBox, bool>( |
|
|
|
nameof(CanPaste), |
|
|
|
o => o.CanPaste); |
|
|
|
AvaloniaProperty.RegisterDirect<TextBox, bool>( |
|
|
|
nameof(CanPaste), |
|
|
|
o => o.CanPaste); |
|
|
|
|
|
|
|
public static readonly StyledProperty<bool> IsUndoEnabledProperty = |
|
|
|
AvaloniaProperty.Register<TextBox, bool>( |
|
|
|
nameof(IsUndoEnabled), |
|
|
|
defaultValue: true); |
|
|
|
|
|
|
|
public static readonly DirectProperty<TextBox, int> UndoLimitProperty = |
|
|
|
AvaloniaProperty.RegisterDirect<TextBox, int>( |
|
|
|
nameof(UndoLimit), |
|
|
|
o => o.UndoLimit, |
|
|
|
(o, v) => o.UndoLimit = v, |
|
|
|
unsetValue: -1); |
|
|
|
|
|
|
|
struct UndoRedoState : IEquatable<UndoRedoState> |
|
|
|
{ |
|
|
|
@ -218,7 +230,7 @@ namespace Avalonia.Controls |
|
|
|
value = CoerceCaretIndex(value); |
|
|
|
SetAndRaise(CaretIndexProperty, ref _caretIndex, value); |
|
|
|
UndoRedoState state; |
|
|
|
if (_undoRedoHelper.TryGetLastState(out state) && state.Text == Text) |
|
|
|
if (IsUndoEnabled && _undoRedoHelper.TryGetLastState(out state) && state.Text == Text) |
|
|
|
_undoRedoHelper.UpdateLastState(); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -316,7 +328,7 @@ namespace Avalonia.Controls |
|
|
|
SelectionEnd = CoerceCaretIndex(SelectionEnd, value); |
|
|
|
CaretIndex = CoerceCaretIndex(caretIndex, value); |
|
|
|
|
|
|
|
if (SetAndRaise(TextProperty, ref _text, value) && !_isUndoingRedoing) |
|
|
|
if (SetAndRaise(TextProperty, ref _text, value) && IsUndoEnabled && !_isUndoingRedoing) |
|
|
|
{ |
|
|
|
_undoRedoHelper.Clear(); |
|
|
|
} |
|
|
|
@ -329,7 +341,7 @@ namespace Avalonia.Controls |
|
|
|
get { return GetSelection(); } |
|
|
|
set |
|
|
|
{ |
|
|
|
_undoRedoHelper.Snapshot(); |
|
|
|
SnapshotUndoRedo(); |
|
|
|
if (string.IsNullOrEmpty(value)) |
|
|
|
{ |
|
|
|
DeleteSelection(); |
|
|
|
@ -338,7 +350,7 @@ namespace Avalonia.Controls |
|
|
|
{ |
|
|
|
HandleTextInput(value); |
|
|
|
} |
|
|
|
_undoRedoHelper.Snapshot(); |
|
|
|
SnapshotUndoRedo(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -446,6 +458,36 @@ namespace Avalonia.Controls |
|
|
|
private set { SetAndRaise(CanPasteProperty, ref _canPaste, value); } |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Property for determining whether undo/redo is enabled
|
|
|
|
/// </summary>
|
|
|
|
public bool IsUndoEnabled |
|
|
|
{ |
|
|
|
get { return GetValue(IsUndoEnabledProperty); } |
|
|
|
set { SetValue(IsUndoEnabledProperty, value); } |
|
|
|
} |
|
|
|
|
|
|
|
public int UndoLimit |
|
|
|
{ |
|
|
|
get { return _undoRedoHelper.Limit; } |
|
|
|
set |
|
|
|
{ |
|
|
|
if (_undoRedoHelper.Limit != value) |
|
|
|
{ |
|
|
|
// can't use SetAndRaise due to using _undoRedoHelper.Limit
|
|
|
|
// (can't send a ref of a property to SetAndRaise),
|
|
|
|
// so use RaisePropertyChanged instead.
|
|
|
|
var oldValue = _undoRedoHelper.Limit; |
|
|
|
_undoRedoHelper.Limit = value; |
|
|
|
RaisePropertyChanged(UndoLimitProperty, oldValue, value); |
|
|
|
} |
|
|
|
// from docs at
|
|
|
|
// https://docs.microsoft.com/en-us/dotnet/api/system.windows.controls.primitives.textboxbase.isundoenabled:
|
|
|
|
// "Setting UndoLimit clears the undo queue."
|
|
|
|
_undoRedoHelper.Clear(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
protected override void OnApplyTemplate(TemplateAppliedEventArgs e) |
|
|
|
{ |
|
|
|
_presenter = e.NameScope.Get<TextPresenter>("PART_TextPresenter"); |
|
|
|
@ -465,6 +507,15 @@ namespace Avalonia.Controls |
|
|
|
UpdatePseudoclasses(); |
|
|
|
UpdateCommandStates(); |
|
|
|
} |
|
|
|
else if (change.Property == IsUndoEnabledProperty && change.NewValue.GetValueOrDefault<bool>() == false) |
|
|
|
{ |
|
|
|
// from docs at
|
|
|
|
// https://docs.microsoft.com/en-us/dotnet/api/system.windows.controls.primitives.textboxbase.isundoenabled:
|
|
|
|
// "Setting this property to false clears the undo stack.
|
|
|
|
// 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."
|
|
|
|
_undoRedoHelper.Clear(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private void UpdateCommandStates() |
|
|
|
@ -551,7 +602,10 @@ namespace Avalonia.Controls |
|
|
|
SetTextInternal(text.Substring(0, caretIndex) + input + text.Substring(caretIndex)); |
|
|
|
CaretIndex += input.Length; |
|
|
|
ClearSelection(); |
|
|
|
_undoRedoHelper.DiscardRedo(); |
|
|
|
if (IsUndoEnabled) |
|
|
|
{ |
|
|
|
_undoRedoHelper.DiscardRedo(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -570,10 +624,10 @@ namespace Avalonia.Controls |
|
|
|
var text = GetSelection(); |
|
|
|
if (text is null) return; |
|
|
|
|
|
|
|
_undoRedoHelper.Snapshot(); |
|
|
|
SnapshotUndoRedo(); |
|
|
|
Copy(); |
|
|
|
DeleteSelection(); |
|
|
|
_undoRedoHelper.Snapshot(); |
|
|
|
SnapshotUndoRedo(); |
|
|
|
} |
|
|
|
|
|
|
|
public async void Copy() |
|
|
|
@ -591,9 +645,9 @@ namespace Avalonia.Controls |
|
|
|
|
|
|
|
if (text is null) return; |
|
|
|
|
|
|
|
_undoRedoHelper.Snapshot(); |
|
|
|
SnapshotUndoRedo(); |
|
|
|
HandleTextInput(text); |
|
|
|
_undoRedoHelper.Snapshot(); |
|
|
|
SnapshotUndoRedo(); |
|
|
|
} |
|
|
|
|
|
|
|
protected override void OnKeyDown(KeyEventArgs e) |
|
|
|
@ -638,7 +692,7 @@ namespace Avalonia.Controls |
|
|
|
Paste(); |
|
|
|
handled = true; |
|
|
|
} |
|
|
|
else if (Match(keymap.Undo)) |
|
|
|
else if (Match(keymap.Undo) && IsUndoEnabled) |
|
|
|
{ |
|
|
|
try |
|
|
|
{ |
|
|
|
@ -652,7 +706,7 @@ namespace Avalonia.Controls |
|
|
|
|
|
|
|
handled = true; |
|
|
|
} |
|
|
|
else if (Match(keymap.Redo)) |
|
|
|
else if (Match(keymap.Redo) && IsUndoEnabled) |
|
|
|
{ |
|
|
|
try |
|
|
|
{ |
|
|
|
@ -752,7 +806,7 @@ namespace Avalonia.Controls |
|
|
|
break; |
|
|
|
|
|
|
|
case Key.Back: |
|
|
|
_undoRedoHelper.Snapshot(); |
|
|
|
SnapshotUndoRedo(); |
|
|
|
if (hasWholeWordModifiers && SelectionStart == SelectionEnd) |
|
|
|
{ |
|
|
|
SetSelectionForControlBackspace(); |
|
|
|
@ -776,13 +830,13 @@ namespace Avalonia.Controls |
|
|
|
CaretIndex -= removedCharacters; |
|
|
|
ClearSelection(); |
|
|
|
} |
|
|
|
_undoRedoHelper.Snapshot(); |
|
|
|
SnapshotUndoRedo(); |
|
|
|
|
|
|
|
handled = true; |
|
|
|
break; |
|
|
|
|
|
|
|
case Key.Delete: |
|
|
|
_undoRedoHelper.Snapshot(); |
|
|
|
SnapshotUndoRedo(); |
|
|
|
if (hasWholeWordModifiers && SelectionStart == SelectionEnd) |
|
|
|
{ |
|
|
|
SetSelectionForControlDelete(); |
|
|
|
@ -804,7 +858,7 @@ namespace Avalonia.Controls |
|
|
|
SetTextInternal(text.Substring(0, caretIndex) + |
|
|
|
text.Substring(caretIndex + removedCharacters)); |
|
|
|
} |
|
|
|
_undoRedoHelper.Snapshot(); |
|
|
|
SnapshotUndoRedo(); |
|
|
|
|
|
|
|
handled = true; |
|
|
|
break; |
|
|
|
@ -812,9 +866,9 @@ namespace Avalonia.Controls |
|
|
|
case Key.Enter: |
|
|
|
if (AcceptsReturn) |
|
|
|
{ |
|
|
|
_undoRedoHelper.Snapshot(); |
|
|
|
SnapshotUndoRedo(); |
|
|
|
HandleTextInput(NewLine); |
|
|
|
_undoRedoHelper.Snapshot(); |
|
|
|
SnapshotUndoRedo(); |
|
|
|
handled = true; |
|
|
|
} |
|
|
|
|
|
|
|
@ -823,9 +877,9 @@ namespace Avalonia.Controls |
|
|
|
case Key.Tab: |
|
|
|
if (AcceptsTab) |
|
|
|
{ |
|
|
|
_undoRedoHelper.Snapshot(); |
|
|
|
SnapshotUndoRedo(); |
|
|
|
HandleTextInput("\t"); |
|
|
|
_undoRedoHelper.Snapshot(); |
|
|
|
SnapshotUndoRedo(); |
|
|
|
handled = true; |
|
|
|
} |
|
|
|
else |
|
|
|
@ -1251,5 +1305,13 @@ namespace Avalonia.Controls |
|
|
|
ClearSelection(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private void SnapshotUndoRedo() |
|
|
|
{ |
|
|
|
if (IsUndoEnabled) |
|
|
|
{ |
|
|
|
_undoRedoHelper.Snapshot(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|