From b3385c08606108cf79c089d604ed2be052429973 Mon Sep 17 00:00:00 2001 From: Qrakhen Date: Sat, 22 Nov 2025 17:34:27 +0100 Subject: [PATCH] stoff --- Qrakhen.Qamp.Editor/Controls/Caret.cs | 44 ++-- Qrakhen.Qamp.Editor/Controls/EditorFrame.xaml | 54 +++-- .../Controls/EditorFrame.xaml.cs | 212 ++++++++++-------- .../Controls/LineRenderer.xaml.cs | 5 - Qrakhen.Qamp.Editor/MainWindow.xaml | 89 +++++--- .../ViewModel/EditorFrameViewModel.cs | 50 +++-- 6 files changed, 269 insertions(+), 185 deletions(-) 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); }