From 6bc7bf4285b853192047cd4472c8503f4f894ca1 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 19 Sep 2022 09:58:48 +0200 Subject: [PATCH 1/4] Synchronize upstream code Remove the _documentSize var and directly use the _scrollExtent, like the upstream project. Cleanup commented code. --- src/AvaloniaEdit/Rendering/TextView.cs | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/src/AvaloniaEdit/Rendering/TextView.cs b/src/AvaloniaEdit/Rendering/TextView.cs index f4da104c..c0f9de14 100644 --- a/src/AvaloniaEdit/Rendering/TextView.cs +++ b/src/AvaloniaEdit/Rendering/TextView.cs @@ -873,8 +873,6 @@ protected override Size MeasureOverride(Size availableSize) layer.Measure(availableSize); } - //InvalidateVisual(); // = InvalidateArrange+InvalidateRender - MeasureInlineObjects(); double maxWidth; @@ -924,9 +922,6 @@ protected override Size MeasureOverride(Size availableSize) new Size(maxWidth, heightTreeHeight), _scrollOffset); - // Size of control (scorll viewport) might be changed during ArrageOverride. We only need document size for now. - _documentSize = new Size(maxWidth, heightTreeHeight); - VisualLinesChanged?.Invoke(this, EventArgs.Empty); return new Size(Math.Min(availableSize.Width, maxWidth), Math.Min(availableSize.Height, heightTreeHeight)); @@ -1152,13 +1147,13 @@ protected override Size ArrangeOverride(Size finalSize) // validate scroll position var newScrollOffsetX = _scrollOffset.X; var newScrollOffsetY = _scrollOffset.Y; - if (_scrollOffset.X + finalSize.Width > _documentSize.Width) + if (_scrollOffset.X + finalSize.Width > _scrollExtent.Width) { - newScrollOffsetX = Math.Max(0, _documentSize.Width - finalSize.Width); + newScrollOffsetX = Math.Max(0, _scrollExtent.Width - finalSize.Width); } - if (_scrollOffset.Y + finalSize.Height > _documentSize.Height) + if (_scrollOffset.Y + finalSize.Height > _scrollExtent.Height) { - newScrollOffsetY = Math.Max(0, _documentSize.Height - finalSize.Height); + newScrollOffsetY = Math.Max(0, _scrollExtent.Height - finalSize.Height); } // Apply final view port and offset @@ -1317,11 +1312,6 @@ internal void ArrangeTextLayer(IList visuals) /// private Size _scrollExtent; - /// - /// Size of the document, in pixels. - /// - private Size _documentSize; - /// /// Offset of the scroll position. /// @@ -2052,7 +2042,7 @@ bool ILogicalScrollable.CanVerticallyScroll } } - bool ILogicalScrollable.IsLogicalScrollEnabled => true; + bool ILogicalScrollable.IsLogicalScrollEnabled => true; Size ILogicalScrollable.ScrollSize => new Size(10, 50); From ce786ab73e2c54f9244af5a83f2919f10f2087bd Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 19 Sep 2022 10:23:58 +0200 Subject: [PATCH 2/4] Fix AllowScrollBelowDocument This commit fixes AllowScrollBelowDocument option. The events chain in the ScrollViewer prevented AvaloniaEdit to reserve more space because when the scrollbar reached the max viewport no new events were send, so the code did not work as WPF. Instead, I changed the implementation to behave as Visual Studio / Visual Studio Code / Sublime. They basically adds an extra Bounds.Height - minimum distance (tipically one line) when the option is enabled. --- src/AvaloniaEdit/Rendering/TextView.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/AvaloniaEdit/Rendering/TextView.cs b/src/AvaloniaEdit/Rendering/TextView.cs index c0f9de14..d6e922d4 100644 --- a/src/AvaloniaEdit/Rendering/TextView.cs +++ b/src/AvaloniaEdit/Rendering/TextView.cs @@ -872,7 +872,7 @@ protected override Size MeasureOverride(Size availableSize) foreach (var layer in Layers) { layer.Measure(availableSize); } - + MeasureInlineObjects(); double maxWidth; @@ -902,6 +902,8 @@ protected override Size MeasureOverride(Size availableSize) maxWidth += AdditionalHorizontalScrollAmount; var heightTreeHeight = DocumentHeight; var options = Options; + double desiredHeight = Math.Min(availableSize.Height, heightTreeHeight); + double extraHeightToAllowScrollBelowDocument = 0; if (options.AllowScrollBelowDocument) { if (!double.IsInfinity(_scrollViewport.Height)) @@ -909,22 +911,20 @@ protected override Size MeasureOverride(Size availableSize) // HACK: we need to keep at least Caret.MinimumDistanceToViewBorder visible so that we don't scroll back up when the user types after // scrolling to the very bottom. var minVisibleDocumentHeight = Math.Max(DefaultLineHeight, Caret.MinimumDistanceToViewBorder); - // scrollViewportBottom: bottom of scroll view port, but clamped so that at least minVisibleDocumentHeight of the document stays visible. - var scrollViewportBottom = Math.Min(heightTreeHeight - minVisibleDocumentHeight, _scrollOffset.Y) + _scrollViewport.Height; // increase the extend height to allow scrolling below the document - heightTreeHeight = Math.Max(heightTreeHeight, scrollViewportBottom); + extraHeightToAllowScrollBelowDocument = desiredHeight - minVisibleDocumentHeight; } } TextLayer.SetVisualLines(_visibleVisualLines); SetScrollData(availableSize, - new Size(maxWidth, heightTreeHeight), + new Size(maxWidth, heightTreeHeight + extraHeightToAllowScrollBelowDocument), _scrollOffset); VisualLinesChanged?.Invoke(this, EventArgs.Empty); - return new Size(Math.Min(availableSize.Width, maxWidth), Math.Min(availableSize.Height, heightTreeHeight)); + return new Size(Math.Min(availableSize.Width, maxWidth), desiredHeight); } /// From c996c3b9d12c832ca3b9f53437660ab190524dae Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 19 Sep 2022 11:34:52 +0200 Subject: [PATCH 3/4] Subscribe FontFamily and FontSize property changes in the TextEditor and set them to the TextView to cause it to call InvalidateDefaultTextMetrics() --- src/AvaloniaEdit/Rendering/TextView.cs | 14 ++++++++++++-- src/AvaloniaEdit/TextEditor.cs | 17 +++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/AvaloniaEdit/Rendering/TextView.cs b/src/AvaloniaEdit/Rendering/TextView.cs index d6e922d4..b6e8d534 100644 --- a/src/AvaloniaEdit/Rendering/TextView.cs +++ b/src/AvaloniaEdit/Rendering/TextView.cs @@ -116,7 +116,17 @@ public TextDocument Document set => SetValue(DocumentProperty, value); } - internal double FontSize => GetValue(TextBlock.FontSizeProperty); + internal double FontSize + { + get => GetValue(TemplatedControl.FontSizeProperty); + set => SetValue(TemplatedControl.FontSizeProperty, value); + } + + internal FontFamily FontFamily + { + get => GetValue(TemplatedControl.FontFamilyProperty); + set => SetValue(TemplatedControl.FontFamilyProperty, value); + } /// /// Occurs when the document property has changed. @@ -910,7 +920,7 @@ protected override Size MeasureOverride(Size availableSize) { // HACK: we need to keep at least Caret.MinimumDistanceToViewBorder visible so that we don't scroll back up when the user types after // scrolling to the very bottom. - var minVisibleDocumentHeight = Math.Max(DefaultLineHeight, Caret.MinimumDistanceToViewBorder); + var minVisibleDocumentHeight = DefaultLineHeight; // increase the extend height to allow scrolling below the document extraHeightToAllowScrollBelowDocument = desiredHeight - minVisibleDocumentHeight; } diff --git a/src/AvaloniaEdit/TextEditor.cs b/src/AvaloniaEdit/TextEditor.cs index 575f4c07..0aeae1b9 100644 --- a/src/AvaloniaEdit/TextEditor.cs +++ b/src/AvaloniaEdit/TextEditor.cs @@ -59,6 +59,8 @@ static TextEditor() IsModifiedProperty.Changed.Subscribe(OnIsModifiedChanged); ShowLineNumbersProperty.Changed.Subscribe(OnShowLineNumbersChanged); LineNumbersForegroundProperty.Changed.Subscribe(OnLineNumbersForegroundChanged); + FontFamilyProperty.Changed.Subscribe(OnFontFamilyPropertyChanged); + FontSizeProperty.Changed.Subscribe(OnFontSizePropertyChanged); } /// @@ -562,6 +564,21 @@ private static void OnLineNumbersForegroundChanged(AvaloniaPropertyChangedEventA lineNumberMargin?.SetValue(ForegroundProperty, e.NewValue); } + + private static void OnFontFamilyPropertyChanged(AvaloniaPropertyChangedEventArgs e) + { + var editor = e.Sender as TextEditor; + + editor?.TextArea.TextView.SetValue(FontFamilyProperty, e.NewValue); + } + + private static void OnFontSizePropertyChanged(AvaloniaPropertyChangedEventArgs e) + { + var editor = e.Sender as TextEditor; + + editor?.TextArea.TextView.SetValue(FontSizeProperty, e.NewValue); + } + #endregion #region TextBoxBase-like methods From f59d3ef7c103c4153f82223120f25c21f54ff94d Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 19 Sep 2022 11:35:42 +0200 Subject: [PATCH 4/4] Do not use margins when bringing the caret into the view to avoid scroll jumps just align the line top to the view, as other editor do (VS, VSCode, Sublime) --- src/AvaloniaEdit/Editing/Caret.cs | 4 ++-- src/AvaloniaEdit/Editing/LineNumberMargin.cs | 4 ++-- src/AvaloniaEdit/Editing/SelectionMouseHandler.cs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/AvaloniaEdit/Editing/Caret.cs b/src/AvaloniaEdit/Editing/Caret.cs index 8f413e62..7148845e 100644 --- a/src/AvaloniaEdit/Editing/Caret.cs +++ b/src/AvaloniaEdit/Editing/Caret.cs @@ -452,14 +452,14 @@ public Rect CalculateCaretRectangle() /// /// Minimum distance of the caret to the view border. /// - internal const double MinimumDistanceToViewBorder = 30; + internal const double MinimumDistanceToViewBorder = 0; /// /// Scrolls the text view so that the caret is visible. /// public void BringCaretToView() { - BringCaretToView(MinimumDistanceToViewBorder); + BringCaretToView(0); } public void BringCaretToView(double border) diff --git a/src/AvaloniaEdit/Editing/LineNumberMargin.cs b/src/AvaloniaEdit/Editing/LineNumberMargin.cs index 32c5f4a2..19bb2747 100644 --- a/src/AvaloniaEdit/Editing/LineNumberMargin.cs +++ b/src/AvaloniaEdit/Editing/LineNumberMargin.cs @@ -177,7 +177,7 @@ protected override void OnPointerPressed(PointerPressedEventArgs e) { ExtendSelection(currentSeg); } - TextArea.Caret.BringCaretToView(5.0); + TextArea.Caret.BringCaretToView(0); } } } @@ -223,7 +223,7 @@ protected override void OnPointerMoved(PointerEventArgs e) if (currentSeg == SimpleSegment.Invalid) return; ExtendSelection(currentSeg); - TextArea.Caret.BringCaretToView(5.0); + TextArea.Caret.BringCaretToView(0); } base.OnPointerMoved(e); } diff --git a/src/AvaloniaEdit/Editing/SelectionMouseHandler.cs b/src/AvaloniaEdit/Editing/SelectionMouseHandler.cs index 78886485..1625738f 100644 --- a/src/AvaloniaEdit/Editing/SelectionMouseHandler.cs +++ b/src/AvaloniaEdit/Editing/SelectionMouseHandler.cs @@ -704,7 +704,7 @@ private void ExtendSelectionToMouse(PointerEventArgs e) TextArea.Caret.Offset = newWord.Offset < _startWord.Offset ? newWord.Offset : Math.Max(newWord.EndOffset, _startWord.EndOffset); } } - TextArea.Caret.BringCaretToView(5.0); + TextArea.Caret.BringCaretToView(0); } #endregion