202 lines
6.0 KiB
C#
202 lines
6.0 KiB
C#
using Qrakhen.Qamp.Editor.Commands;
|
|
using Qrakhen.Qamp.Editor.Input;
|
|
using Qrakhen.Qamp.Editor.Primitives;
|
|
using Qrakhen.Qamp.Editor.ViewModel;
|
|
using Qrakhen.Qamp.Memory;
|
|
using System.Diagnostics.Eventing.Reader;
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using System.Windows.Documents;
|
|
using System.Windows.Input;
|
|
using System.Windows.Media;
|
|
|
|
namespace Qrakhen.Qamp.Editor.Controls;
|
|
|
|
public partial class EditorFrame : UserControl
|
|
{
|
|
public Caret Caret { get; private set; }
|
|
|
|
public EditorFrame()
|
|
{
|
|
InitializeComponent();
|
|
Loaded += OnLoaded;
|
|
PreviewKeyDown += OnKeyDown;
|
|
PreviewMouseDown += OnMouseDown;
|
|
ScrollView.ScrollChanged += OnScroll;
|
|
}
|
|
|
|
private void OnScroll(object sender, ScrollChangedEventArgs e)
|
|
{
|
|
UpdateCaret(false);
|
|
}
|
|
|
|
protected void OnMouseDown(object sender, MouseButtonEventArgs e)
|
|
{
|
|
if (e.LeftButton == MouseButtonState.Pressed) {
|
|
if (DataContext is EditorFrameViewModel vm) {
|
|
vm.MoveCaretCommand.Execute(
|
|
new MoveCaretOptions(
|
|
CalculateCursorPosition(e.GetPosition(this), 0, 0),
|
|
false,
|
|
false));
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnKeyDown(object sender, KeyEventArgs e)
|
|
{
|
|
if (DataContext is EditorFrameViewModel vm) {
|
|
BufferPosition position = e.Key switch {
|
|
Key.Right => new(0, 1),
|
|
Key.Left => new(0, -1),
|
|
Key.Up => new(-1, 0),
|
|
Key.Down => new(1, 0),
|
|
_ => new(0, 0)
|
|
};
|
|
if (position != BufferPosition.Initial)
|
|
vm.MoveCaretCommand.Execute(
|
|
new MoveCaretOptions(
|
|
position,
|
|
true,
|
|
InputService.CtrlHeld));
|
|
else if (e.Key == Key.Back)
|
|
vm.DeleteCommand.Execute(-1);
|
|
else if (e.Key == Key.Delete)
|
|
vm.DeleteCommand.Execute(1);
|
|
else if (e.Key == Key.Enter)
|
|
vm.InsertCommand.Execute(Environment.NewLine);
|
|
else if (e.Key == Key.Delete)
|
|
vm.DeleteCommand.Execute(1);
|
|
else {
|
|
char c = KeyHelper.Get(e.Key,
|
|
InputService.ShiftHeld ? 1 :
|
|
(InputService.CtrlHeld && InputService.AltHeld) ? 2 : 0);
|
|
if (c != 0)
|
|
vm.InsertCommand.Execute(c);
|
|
}
|
|
|
|
e.Handled = true;
|
|
}
|
|
}
|
|
|
|
private void OnLoaded(object sender, RoutedEventArgs e)
|
|
{
|
|
Focus();
|
|
AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this);
|
|
if (adornerLayer != null) {
|
|
Caret = new Caret(LineList, Brushes.LimeGreen);
|
|
adornerLayer.Add(Caret);
|
|
} else {
|
|
System.Diagnostics.Debug.WriteLine("AdornerLayer still null. Check parent hierarchy.");
|
|
}
|
|
Loaded -= OnLoaded;
|
|
}
|
|
|
|
private BufferPosition CalculateCursorPosition(Point point, double scrollY, double scrollX)
|
|
{
|
|
var ft = TextHelper.GetText(new string('_', 1), 14, null, VisualTreeHelper.GetDpi(this).PixelsPerDip);
|
|
return new BufferPosition((int)(point.Y / TextHelper.LineHeight), (int)((point.X - 2) / ft.Width));
|
|
}
|
|
|
|
private Point CalculateCaretPosition(int line, int index, double scrollY, double scrollX)
|
|
{
|
|
var ft = TextHelper.GetText(new string('_', index), 14, null, VisualTreeHelper.GetDpi(this).PixelsPerDip);
|
|
return new Point(ft.Width + 2, line * TextHelper.LineHeight);
|
|
}
|
|
|
|
private void MoveCaret(Point point)
|
|
{
|
|
Caret?.UpdatePosition(point);
|
|
}
|
|
|
|
private void HideCaret()
|
|
{
|
|
Caret?.Disable();
|
|
}
|
|
|
|
private void AutoScroll(Point point)
|
|
{
|
|
MoveCaret(point);
|
|
}
|
|
|
|
private void UpdateCaret(bool autoScroll = true)
|
|
{
|
|
int line = CursorPosition.Line;
|
|
int charIndex = CursorPosition.Column;
|
|
|
|
double scrollY = ScrollView.VerticalOffset;
|
|
double scrollX = ScrollView.HorizontalOffset;
|
|
|
|
Point position = CalculateCaretPosition(
|
|
line,
|
|
charIndex,
|
|
scrollY,
|
|
scrollX);
|
|
|
|
Point offset = ScrollView.TranslatePoint(position, ScrollView);
|
|
|
|
if (offset.X < 0 ||
|
|
offset.Y < 0 ||
|
|
offset.X >= ScrollView.ActualWidth ||
|
|
offset.Y >= ScrollView.ActualHeight) {
|
|
if (autoScroll)
|
|
AutoScroll(offset);
|
|
else
|
|
HideCaret();
|
|
} else
|
|
MoveCaret(position);
|
|
|
|
if (!CurrentSelection.IsVoid) {
|
|
|
|
}
|
|
}
|
|
|
|
public LineBuffer CurrentLineBuffer {
|
|
get => (LineBuffer)GetValue(CurrentLineBufferProperty);
|
|
set => SetValue(CurrentLineBufferProperty, value);
|
|
}
|
|
|
|
public static readonly DependencyProperty CurrentLineBufferProperty =
|
|
DependencyProperty.Register(
|
|
nameof(CurrentLineBuffer),
|
|
typeof(LineBuffer),
|
|
typeof(EditorFrame),
|
|
new PropertyMetadata(null));
|
|
|
|
public BufferPosition CursorPosition {
|
|
get => (BufferPosition)GetValue(CursorPositionProperty);
|
|
set => SetValue(CursorPositionProperty, value);
|
|
}
|
|
|
|
public static readonly DependencyProperty CursorPositionProperty =
|
|
DependencyProperty.Register(
|
|
nameof(CursorPosition),
|
|
typeof(BufferPosition),
|
|
typeof(EditorFrame),
|
|
new PropertyMetadata(BufferPosition.Initial, OnCursorPositionChanged));
|
|
|
|
private static void OnCursorPositionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
|
{
|
|
var frame = (EditorFrame)d;
|
|
frame.UpdateCaret();
|
|
}
|
|
|
|
public BufferRegion CurrentSelection {
|
|
get => (BufferRegion)GetValue(CurrentSelectionProperty);
|
|
set => SetValue(CurrentSelectionProperty, value);
|
|
}
|
|
|
|
public static readonly DependencyProperty CurrentSelectionProperty =
|
|
DependencyProperty.Register(
|
|
nameof(CurrentSelection),
|
|
typeof(BufferRegion),
|
|
typeof(EditorFrame),
|
|
new PropertyMetadata(BufferRegion.Void, OnCurrentSelectionChanged));
|
|
|
|
private static void OnCurrentSelectionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
|
{
|
|
var frame = (EditorFrame)d;
|
|
frame.UpdateCaret();
|
|
}
|
|
}
|