130 lines
3.4 KiB
C#
130 lines
3.4 KiB
C#
using System;
|
|
using Avalonia;
|
|
using Avalonia.Controls;
|
|
using Avalonia.Input;
|
|
using Avalonia.Layout;
|
|
using Avalonia.Media;
|
|
|
|
namespace Minint.Controls;
|
|
|
|
/// <summary>
|
|
/// Shows a TextBlock by default; switches to an inline TextBox on double-click.
|
|
/// Commits on Enter or focus loss, cancels on Escape.
|
|
/// </summary>
|
|
public class EditableTextBlock : Control
|
|
{
|
|
public static readonly StyledProperty<string> TextProperty =
|
|
AvaloniaProperty.Register<EditableTextBlock, string>(nameof(Text), defaultBindingMode: Avalonia.Data.BindingMode.TwoWay);
|
|
|
|
public string Text
|
|
{
|
|
get => GetValue(TextProperty);
|
|
set => SetValue(TextProperty, value);
|
|
}
|
|
|
|
private readonly TextBlock _display;
|
|
private readonly TextBox _editor;
|
|
private bool _isEditing;
|
|
|
|
public EditableTextBlock()
|
|
{
|
|
_display = new TextBlock
|
|
{
|
|
VerticalAlignment = VerticalAlignment.Center,
|
|
TextTrimming = TextTrimming.CharacterEllipsis,
|
|
};
|
|
|
|
_editor = new TextBox
|
|
{
|
|
VerticalAlignment = VerticalAlignment.Center,
|
|
Padding = new Thickness(2, 0),
|
|
BorderThickness = new Thickness(1),
|
|
MinWidth = 40,
|
|
IsVisible = false,
|
|
};
|
|
|
|
LogicalChildren.Add(_display);
|
|
LogicalChildren.Add(_editor);
|
|
VisualChildren.Add(_display);
|
|
VisualChildren.Add(_editor);
|
|
|
|
_display.Bind(TextBlock.TextProperty, this.GetObservable(TextProperty).ToBinding());
|
|
_editor.Bind(TextBox.TextProperty, this.GetObservable(TextProperty).ToBinding());
|
|
|
|
_editor.KeyDown += OnEditorKeyDown;
|
|
_editor.LostFocus += OnEditorLostFocus;
|
|
}
|
|
|
|
protected override void OnPointerPressed(PointerPressedEventArgs e)
|
|
{
|
|
base.OnPointerPressed(e);
|
|
if (e.ClickCount == 2 && !_isEditing)
|
|
{
|
|
BeginEdit();
|
|
e.Handled = true;
|
|
}
|
|
}
|
|
|
|
private void BeginEdit()
|
|
{
|
|
_isEditing = true;
|
|
_editor.Text = Text;
|
|
_display.IsVisible = false;
|
|
_editor.IsVisible = true;
|
|
_editor.Focus();
|
|
_editor.SelectAll();
|
|
}
|
|
|
|
private void CommitEdit()
|
|
{
|
|
if (!_isEditing) return;
|
|
_isEditing = false;
|
|
Text = _editor.Text ?? string.Empty;
|
|
_editor.IsVisible = false;
|
|
_display.IsVisible = true;
|
|
}
|
|
|
|
private void CancelEdit()
|
|
{
|
|
if (!_isEditing) return;
|
|
_isEditing = false;
|
|
_editor.Text = Text;
|
|
_editor.IsVisible = false;
|
|
_display.IsVisible = true;
|
|
}
|
|
|
|
private void OnEditorKeyDown(object? sender, KeyEventArgs e)
|
|
{
|
|
if (e.Key == Key.Enter)
|
|
{
|
|
CommitEdit();
|
|
e.Handled = true;
|
|
}
|
|
else if (e.Key == Key.Escape)
|
|
{
|
|
CancelEdit();
|
|
e.Handled = true;
|
|
}
|
|
}
|
|
|
|
private void OnEditorLostFocus(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
|
|
{
|
|
CommitEdit();
|
|
}
|
|
|
|
protected override Size MeasureOverride(Size availableSize)
|
|
{
|
|
_display.Measure(availableSize);
|
|
_editor.Measure(availableSize);
|
|
return _isEditing ? _editor.DesiredSize : _display.DesiredSize;
|
|
}
|
|
|
|
protected override Size ArrangeOverride(Size finalSize)
|
|
{
|
|
var rect = new Rect(finalSize);
|
|
_display.Arrange(rect);
|
|
_editor.Arrange(rect);
|
|
return finalSize;
|
|
}
|
|
}
|