|
@@ -18,6 +18,15 @@ namespace Avalonia.Controls
|
|
|
{
|
|
|
public class TextBox : TemplatedControl, UndoRedoHelper<TextBox.UndoRedoState>.IUndoRedoHost
|
|
|
{
|
|
|
+ public static KeyGesture CutGesture { get; } = AvaloniaLocator.Current
|
|
|
+ .GetService<PlatformHotkeyConfiguration>()?.Cut.FirstOrDefault();
|
|
|
+
|
|
|
+ public static KeyGesture CopyGesture { get; } = AvaloniaLocator.Current
|
|
|
+ .GetService<PlatformHotkeyConfiguration>()?.Copy.FirstOrDefault();
|
|
|
+
|
|
|
+ public static KeyGesture PasteGesture { get; } = AvaloniaLocator.Current
|
|
|
+ .GetService<PlatformHotkeyConfiguration>()?.Paste.FirstOrDefault();
|
|
|
+
|
|
|
public static readonly StyledProperty<bool> AcceptsReturnProperty =
|
|
|
AvaloniaProperty.Register<TextBox, bool>(nameof(AcceptsReturn));
|
|
|
|
|
@@ -103,6 +112,21 @@ namespace Avalonia.Controls
|
|
|
|
|
|
public static readonly StyledProperty<bool> RevealPasswordProperty =
|
|
|
AvaloniaProperty.Register<TextBox, bool>(nameof(RevealPassword));
|
|
|
+
|
|
|
+ public static readonly DirectProperty<TextBox, bool> CanCutProperty =
|
|
|
+ AvaloniaProperty.RegisterDirect<TextBox, bool>(
|
|
|
+ nameof(CanCut),
|
|
|
+ o => o.CanCut);
|
|
|
+
|
|
|
+ public static readonly DirectProperty<TextBox, bool> CanCopyProperty =
|
|
|
+ AvaloniaProperty.RegisterDirect<TextBox, bool>(
|
|
|
+ nameof(CanCopy),
|
|
|
+ o => o.CanCopy);
|
|
|
+
|
|
|
+ public static readonly DirectProperty<TextBox, bool> CanPasteProperty =
|
|
|
+ AvaloniaProperty.RegisterDirect<TextBox, bool>(
|
|
|
+ nameof(CanPaste),
|
|
|
+ o => o.CanPaste);
|
|
|
|
|
|
struct UndoRedoState : IEquatable<UndoRedoState>
|
|
|
{
|
|
@@ -126,6 +150,9 @@ namespace Avalonia.Controls
|
|
|
private UndoRedoHelper<UndoRedoState> _undoRedoHelper;
|
|
|
private bool _isUndoingRedoing;
|
|
|
private bool _ignoreTextChanges;
|
|
|
+ private bool _canCut;
|
|
|
+ private bool _canCopy;
|
|
|
+ private bool _canPaste;
|
|
|
private string _newLine = Environment.NewLine;
|
|
|
private static readonly string[] invalidCharacters = new String[1] { "\u007f" };
|
|
|
|
|
@@ -370,6 +397,33 @@ namespace Avalonia.Controls
|
|
|
set { SetAndRaise(NewLineProperty, ref _newLine, value); }
|
|
|
}
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// Property for determining if the Cut command can be executed.
|
|
|
+ /// </summary>
|
|
|
+ public bool CanCut
|
|
|
+ {
|
|
|
+ get { return _canCut; }
|
|
|
+ private set { SetAndRaise(CanCutProperty, ref _canCut, value); }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Property for determining if the Copy command can be executed.
|
|
|
+ /// </summary>
|
|
|
+ public bool CanCopy
|
|
|
+ {
|
|
|
+ get { return _canCopy; }
|
|
|
+ private set { SetAndRaise(CanCopyProperty, ref _canCopy, value); }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Property for determining if the Paste command can be executed.
|
|
|
+ /// </summary>
|
|
|
+ public bool CanPaste
|
|
|
+ {
|
|
|
+ get { return _canPaste; }
|
|
|
+ private set { SetAndRaise(CanPasteProperty, ref _canPaste, value); }
|
|
|
+ }
|
|
|
+
|
|
|
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
|
|
{
|
|
|
_presenter = e.NameScope.Get<TextPresenter>("PART_TextPresenter");
|
|
@@ -387,9 +441,19 @@ namespace Avalonia.Controls
|
|
|
if (change.Property == TextProperty)
|
|
|
{
|
|
|
UpdatePseudoclasses();
|
|
|
+ UpdateCommandStates();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ private void UpdateCommandStates()
|
|
|
+ {
|
|
|
+ var text = GetSelection();
|
|
|
+ var b1 = string.IsNullOrEmpty(text);
|
|
|
+ CanCopy = !b1;
|
|
|
+ CanCut = !b1;
|
|
|
+ CanPaste = !IsReadOnly;
|
|
|
+ }
|
|
|
+
|
|
|
protected override void OnGotFocus(GotFocusEventArgs e)
|
|
|
{
|
|
|
base.OnGotFocus(e);
|
|
@@ -404,6 +468,8 @@ namespace Avalonia.Controls
|
|
|
SelectAll();
|
|
|
}
|
|
|
|
|
|
+ UpdateCommandStates();
|
|
|
+
|
|
|
_presenter?.ShowCaret();
|
|
|
}
|
|
|
|
|
@@ -417,7 +483,9 @@ namespace Avalonia.Controls
|
|
|
SelectionEnd = 0;
|
|
|
RevealPassword = false;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
+ UpdateCommandStates();
|
|
|
+
|
|
|
_presenter?.HideCaret();
|
|
|
}
|
|
|
|
|
@@ -460,19 +528,31 @@ namespace Avalonia.Controls
|
|
|
return text;
|
|
|
}
|
|
|
|
|
|
- private async void Copy()
|
|
|
+ public async void Cut()
|
|
|
+ {
|
|
|
+ var text = GetSelection();
|
|
|
+ if (text is null) return;
|
|
|
+
|
|
|
+ _undoRedoHelper.Snapshot();
|
|
|
+ Copy();
|
|
|
+ DeleteSelection();
|
|
|
+ _undoRedoHelper.Snapshot();
|
|
|
+ }
|
|
|
+
|
|
|
+ public async void Copy()
|
|
|
{
|
|
|
+ var text = GetSelection();
|
|
|
+ if (text is null) return;
|
|
|
+
|
|
|
await ((IClipboard)AvaloniaLocator.Current.GetService(typeof(IClipboard)))
|
|
|
- .SetTextAsync(GetSelection());
|
|
|
+ .SetTextAsync(text);
|
|
|
}
|
|
|
|
|
|
- private async void Paste()
|
|
|
+ public async void Paste()
|
|
|
{
|
|
|
var text = await ((IClipboard)AvaloniaLocator.Current.GetService(typeof(IClipboard))).GetTextAsync();
|
|
|
- if (text == null)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
+
|
|
|
+ if (text is null) return;
|
|
|
|
|
|
_undoRedoHelper.Snapshot();
|
|
|
HandleTextInput(text);
|
|
@@ -511,23 +591,18 @@ namespace Avalonia.Controls
|
|
|
{
|
|
|
if (!IsPasswordBox)
|
|
|
{
|
|
|
- _undoRedoHelper.Snapshot();
|
|
|
- Copy();
|
|
|
- DeleteSelection();
|
|
|
- _undoRedoHelper.Snapshot();
|
|
|
+ Cut();
|
|
|
}
|
|
|
|
|
|
handled = true;
|
|
|
}
|
|
|
else if (Match(keymap.Paste))
|
|
|
{
|
|
|
-
|
|
|
Paste();
|
|
|
handled = true;
|
|
|
}
|
|
|
else if (Match(keymap.Undo))
|
|
|
{
|
|
|
-
|
|
|
try
|
|
|
{
|
|
|
_isUndoingRedoing = true;
|