diff --git a/Qrakhen.Qamp.Editor/Controls/Caret.cs b/Qrakhen.Qamp.Editor/Controls/Caret.cs
index 5ae77d9..18b49c1 100644
--- a/Qrakhen.Qamp.Editor/Controls/Caret.cs
+++ b/Qrakhen.Qamp.Editor/Controls/Caret.cs
@@ -7,26 +7,28 @@ namespace Qrakhen.Qamp.Editor.Controls;
public class Caret : Adorner
{
- private readonly Pen _pen;
- private readonly double _height;
- private readonly Brush _brush;
- private bool _blink;
- private Point _cursorPosition;
- private Point _targetPosition;
+ private readonly Pen _pen;
+ private readonly double _height;
+ private readonly Brush _brush;
+ private bool _blink;
+ private bool _enabled;
+ private Point _cursorPosition;
+ private Point _targetPosition;
private (Point from, Point to)[] _lines = [];
- private DispatcherTimer _blinkTimer;
- private DispatcherTimer _moveTimer;
+ private DispatcherTimer _blinkTimer;
+ private DispatcherTimer _moveTimer;
public Caret(UIElement adornedElement, Brush brush, double height = 18, double thickness = 1.72) : base(adornedElement)
{
IsHitTestVisible = false;
+ _enabled = true;
_height = height;
_brush = brush;
_pen = new Pen(brush, 1.92);
_blinkTimer = new DispatcherTimer();
- _blinkTimer.Interval = TimeSpan.FromMilliseconds(428);
+ _blinkTimer.Interval = TimeSpan.FromMilliseconds(324);
_blinkTimer.Tick += new EventHandler((s, e) => {
Toggle(_blink = !_blink);
});
@@ -50,22 +52,30 @@ public class Caret : Adorner
public void Toggle(bool hide)
{
_pen.Brush = hide ? Brushes.Transparent : _brush;
+ InvalidateVisual();
}
+ public void Disable()
+ {
+ _blinkTimer?.Stop();
+ _enabled = false;
+ Toggle(true);
+ InvalidateVisual();
+ }
+
public void UpdateSelection((Point from, Point to)[] lines)
{
_lines = lines;
InvalidateVisual();
}
- public void UpdatePosition(Point newPosition)
- {
- _cursorPosition = _targetPosition = newPosition;
- Toggle(_blink = false);
- //_blinkTimer.Stop();
- //_moveTimer.Start();
- InvalidateVisual();
- }
+ public void UpdatePosition(Point newPosition)
+ {
+ _cursorPosition = _targetPosition = newPosition;
+ _enabled = true;
+ Toggle(_blink = false);
+ _blinkTimer.Start();
+ }
protected override void OnRender(DrawingContext drawingContext)
{
diff --git a/Qrakhen.Qamp.Editor/Controls/EditorFrame.xaml b/Qrakhen.Qamp.Editor/Controls/EditorFrame.xaml
index ff6ac05..9addae4 100644
--- a/Qrakhen.Qamp.Editor/Controls/EditorFrame.xaml
+++ b/Qrakhen.Qamp.Editor/Controls/EditorFrame.xaml
@@ -15,26 +15,40 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
diff --git a/Qrakhen.Qamp.Editor/Controls/EditorFrame.xaml.cs b/Qrakhen.Qamp.Editor/Controls/EditorFrame.xaml.cs
index a294dbc..9b4d9f3 100644
--- a/Qrakhen.Qamp.Editor/Controls/EditorFrame.xaml.cs
+++ b/Qrakhen.Qamp.Editor/Controls/EditorFrame.xaml.cs
@@ -3,26 +3,32 @@ 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;
-using System.Windows.Shapes;
namespace Qrakhen.Qamp.Editor.Controls;
public partial class EditorFrame : UserControl
{
- public Caret Caret { get; private set; }
+ public Caret Caret { get; private set; }
- public EditorFrame()
- {
- InitializeComponent();
- Loaded += OnLoaded;
- PreviewKeyDown += OnKeyDown;
- PreviewMouseDown += OnMouseDown;
- }
+ 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)
{
@@ -30,133 +36,151 @@ public partial class EditorFrame : UserControl
if (DataContext is EditorFrameViewModel vm) {
vm.MoveCaretCommand.Execute(
new MoveCaretOptions(
- CalculateCursorPosition(e.GetPosition(this), 0, 0),
- false,
+ 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(
+ 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,
+ 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 {
+ 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;
- }
- }
+ e.Handled = true;
+ }
+ }
- private void OnLoaded(object sender, RoutedEventArgs e)
- {
- Focus();
- AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this);
- if (adornerLayer != null) {
- Caret = new Caret(this, Brushes.LimeGreen);
- adornerLayer.Add(Caret);
- } else {
- System.Diagnostics.Debug.WriteLine("AdornerLayer still null. Check parent hierarchy.");
- }
- Loaded -= OnLoaded;
- }
+ private void OnLoaded(object sender, RoutedEventArgs e)
+ {
+ Focus();
+ AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this);
+ if (adornerLayer != null) {
+ Caret = new Caret(this, 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 / ft.Width));
+ return new BufferPosition((int)(point.Y / TextHelper.LineHeight), (int)((point.X - 34) / 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 + scrollX + 2, line * TextHelper.LineHeight + scrollY);
- }
-
- private void MoveCaret(Point point)
- {
- Caret?.UpdatePosition(point);
- }
-
- private void SelectRegion((Point from, Point to)[] lines)
{
- Caret?.UpdateSelection(lines);
+ var ft = TextHelper.GetText(new string('_', index), 14, null, VisualTreeHelper.GetDpi(this).PixelsPerDip);
+ return new Point(ft.Width - scrollX + 34, line * TextHelper.LineHeight - scrollY);
}
- private void UpdateCaret()
- {
- int line = CursorPosition.Line;
- int charIndex = CursorPosition.Column;
+ private void MoveCaret(Point point)
+ {
+ Caret?.UpdatePosition(point);
+ }
- double scrollY = ScrollView.VerticalOffset;
- double scrollX = ScrollView.HorizontalOffset;
+ private void HideCaret()
+ {
+ Caret?.Disable();
+ }
- MoveCaret(
- CalculateCaretPosition(
- line,
- charIndex,
- scrollY,
- scrollX));
+ 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 LineBuffer CurrentLineBuffer {
+ get => (LineBuffer)GetValue(CurrentLineBufferProperty);
+ set => SetValue(CurrentLineBufferProperty, value);
+ }
- public static readonly DependencyProperty CurrentLineBufferProperty =
+ 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 BufferPosition CursorPosition {
+ get => (BufferPosition)GetValue(CursorPositionProperty);
+ set => SetValue(CursorPositionProperty, value);
+ }
- public static readonly DependencyProperty CursorPositionProperty =
+ public static readonly DependencyProperty CursorPositionProperty =
DependencyProperty.Register(
- nameof(CursorPosition),
- typeof(BufferPosition),
- typeof(EditorFrame),
+ 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();
- }
+ private static void OnCursorPositionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ var frame = (EditorFrame)d;
+ frame.UpdateCaret();
+ }
public BufferRegion CurrentSelection {
get => (BufferRegion)GetValue(CurrentSelectionProperty);
diff --git a/Qrakhen.Qamp.Editor/Controls/LineRenderer.xaml.cs b/Qrakhen.Qamp.Editor/Controls/LineRenderer.xaml.cs
index 3a3d474..9b3379d 100644
--- a/Qrakhen.Qamp.Editor/Controls/LineRenderer.xaml.cs
+++ b/Qrakhen.Qamp.Editor/Controls/LineRenderer.xaml.cs
@@ -1,13 +1,8 @@
using Qrakhen.Qamp.Memory;
using System;
-using System.Collections.Generic;
using System.ComponentModel;
-using System.Text;
using System.Windows;
using System.Windows.Controls;
-using System.Windows.Data;
-using System.Windows.Documents;
-using System.Windows.Input;
using System.Windows.Media;
namespace Qrakhen.Qamp.Editor.Controls;
diff --git a/Qrakhen.Qamp.Editor/MainWindow.xaml b/Qrakhen.Qamp.Editor/MainWindow.xaml
index 365ea39..fcd76fc 100644
--- a/Qrakhen.Qamp.Editor/MainWindow.xaml
+++ b/Qrakhen.Qamp.Editor/MainWindow.xaml
@@ -7,39 +7,74 @@
xmlns:vm="clr-namespace:Qrakhen.Qamp.Editor.ViewModel"
xmlns:controls="clr-namespace:Qrakhen.Qamp.Editor.Controls"
mc:Ignorable="d"
- d:DataContext="{d:DesignInstance Type=vm:FileViewModel}"
- Title="MainWindow" Height="450" Width="800">
+ Background="#161718"
+ d:DataContext="{d:DesignInstance Type=vm:MainViewModel}"
+ Title="MainWindow" Height="640" Width="920">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Qrakhen.Qamp.Editor/ViewModel/EditorFrameViewModel.cs b/Qrakhen.Qamp.Editor/ViewModel/EditorFrameViewModel.cs
index 3b3bef5..00c51f5 100644
--- a/Qrakhen.Qamp.Editor/ViewModel/EditorFrameViewModel.cs
+++ b/Qrakhen.Qamp.Editor/ViewModel/EditorFrameViewModel.cs
@@ -8,6 +8,12 @@ using System.Windows.Input;
namespace Qrakhen.Qamp.Editor.ViewModel;
+public class SelectableLineBuffer(LineBuffer buffer)
+{
+ public LineBuffer Buffer { get; private set; } = buffer;
+ public BufferRegion Selection { get; private set; } = new();
+}
+
public class EditorFrameViewModel : ObservableObject
{
private BufferPosition _cursorPosition;
@@ -26,7 +32,7 @@ public class EditorFrameViewModel : ObservableObject
public int CursorColumn => _cursorPosition.Column;
- public LineBuffer CurrentLineBuffer => Lines[CursorLine];
+ public SelectableLineBuffer CurrentLine => Lines[CursorLine];
public ICommand MoveCaretCommand { get; }
public ICommand MoveBlockCommand { get; }
@@ -34,11 +40,11 @@ public class EditorFrameViewModel : ObservableObject
public ICommand DeleteCommand { get; }
public ICommand ClipBoardCommand { get; }
- public ObservableCollection Lines { get; private set; } = new() {
- new LineBuffer("test"),
- new LineBuffer(" is very good;"),
- new LineBuffer(" jaja();"),
- new LineBuffer("}")
+ public ObservableCollection Lines { get; private set; } = new() {
+ new SelectableLineBuffer(new LineBuffer("test {")),
+ new SelectableLineBuffer(new LineBuffer(" is very good;")),
+ new SelectableLineBuffer(new LineBuffer(" jaja();")),
+ new SelectableLineBuffer(new LineBuffer("}"))
};
public EditorFrameViewModel()
@@ -56,14 +62,14 @@ public class EditorFrameViewModel : ObservableObject
public void SetCursor(BufferPosition position)
{
CursorPosition = AlignBufferPosition(position);
- OnPropertyChanged(nameof(CurrentLineBuffer));
+ OnPropertyChanged(nameof(CurrentLine));
}
public void MoveCursor(int lines, int columns) => MoveCursor(new BufferPosition(lines, columns));
public void MoveCursor(BufferPosition relative, bool jump = false)
{
SetCursor(CursorPosition + relative);
- OnPropertyChanged(nameof(CurrentLineBuffer));
+ OnPropertyChanged(nameof(CurrentLine));
}
public void Delete(BufferRegion region, bool follow = true)
@@ -83,25 +89,25 @@ public class EditorFrameViewModel : ObservableObject
if (follow) {
// remove newline
if (CursorColumn - count < 0 && CursorLine > 0) {
- int position = Lines[CursorLine - 1].Tail;
- Lines[CursorLine - 1].Insert(
+ int position = Lines[CursorLine - 1].Buffer.Tail;
+ Lines[CursorLine - 1].Buffer.Insert(
position,
- CurrentLineBuffer.Slice(0));
+ CurrentLine.Buffer.Slice(0));
Lines.RemoveAt(CursorLine);
SetCursor(CursorLine - 1, position);
} else {
MoveCursor(0, -count);
- CurrentLineBuffer.Delete(CursorColumn, count);
+ CurrentLine.Buffer.Delete(CursorColumn, count);
}
} else {
- if (CursorColumn + count > CurrentLineBuffer.Tail &&
+ if (CursorColumn + count > CurrentLine.Buffer.Tail &&
CursorLine < Lines.Count - 1) {
- CurrentLineBuffer.Insert(
- CurrentLineBuffer.Tail,
- Lines[CursorLine + 1].Slice(0));
+ CurrentLine.Buffer.Insert(
+ CurrentLine.Buffer.Tail,
+ Lines[CursorLine + 1].Buffer.Slice(0));
Lines.RemoveAt(CursorLine + 1);
}
- CurrentLineBuffer.Delete(CursorColumn, count);
+ CurrentLine.Buffer.Delete(CursorColumn, count);
}
}
@@ -123,12 +129,12 @@ public class EditorFrameViewModel : ObservableObject
for (int i = 0; i < lines.Length; i++) {
if (i > 0) {
LineBuffer split = new LineBuffer(
- CurrentLineBuffer.Slice(CursorColumn),
- CurrentLineBuffer.Encoding);
- Lines.Insert(CursorLine + 1, split);
+ CurrentLine.Buffer.Slice(CursorColumn),
+ CurrentLine.Buffer.Encoding);
+ Lines.Insert(CursorLine + 1, new SelectableLineBuffer(split));
SetCursor(new BufferPosition(CursorLine + 1, 0));
}
- CurrentLineBuffer.Insert(CursorColumn, lines[i]);
+ CurrentLine.Buffer.Insert(CursorColumn, lines[i]);
if (follow)
MoveCursor(new BufferPosition(0, lines[i].Length));
}
@@ -137,7 +143,7 @@ public class EditorFrameViewModel : ObservableObject
private BufferPosition AlignBufferPosition(BufferPosition position)
{
int line = Math.Max(0, Math.Min(position.Line, Lines.Count - 1));
- LineBuffer buffer = Lines[line];
+ LineBuffer buffer = Lines[line].Buffer;
int column = Math.Max(0, Math.Min(position.Column, buffer.Tail));
return new BufferPosition(line, column);
}