From c57ce7f5fc6345e7036525f2e5740f2ec20b915b Mon Sep 17 00:00:00 2001 From: Murdo R Ergeaux Date: Wed, 19 Aug 2020 17:22:34 +0100 Subject: [PATCH 01/12] Fix Issue 3825 --- src/Avalonia.Visuals/Media/GlyphRun.cs | 4 +--- src/Avalonia.Visuals/Rendering/SceneGraph/GlyphRunNode.cs | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.Visuals/Media/GlyphRun.cs b/src/Avalonia.Visuals/Media/GlyphRun.cs index a32a3e1b6c..da3a1f721c 100644 --- a/src/Avalonia.Visuals/Media/GlyphRun.cs +++ b/src/Avalonia.Visuals/Media/GlyphRun.cs @@ -555,7 +555,7 @@ namespace Avalonia.Media } } - return new Rect(0, 0, width, height); + return new Rect(0, GlyphTypeface.Ascent * Scale, width, height); } private void Set(ref T field, T value) @@ -595,8 +595,6 @@ namespace Avalonia.Media _glyphRunImpl = platformRenderInterface.CreateGlyphRun(this, out var width); var height = (GlyphTypeface.Descent - GlyphTypeface.Ascent + GlyphTypeface.LineGap) * Scale; - - _bounds = new Rect(0, 0, width, height); } void IDisposable.Dispose() diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/GlyphRunNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/GlyphRunNode.cs index eaf4effdbe..bdf05c4f86 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/GlyphRunNode.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/GlyphRunNode.cs @@ -25,7 +25,7 @@ namespace Avalonia.Rendering.SceneGraph GlyphRun glyphRun, Point baselineOrigin, IDictionary childScenes = null) - : base(glyphRun.Bounds, transform) + : base(glyphRun.Bounds.Translate(baselineOrigin), transform) { Transform = transform; Foreground = foreground?.ToImmutable(); From 8af00c9d10a19baa6d281e09b0bac97f1e291812 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Pedro?= Date: Thu, 20 Aug 2020 01:47:50 +0100 Subject: [PATCH 02/12] Relaxed conditions for data context type inference in compiled bindings. --- .../AvaloniaXamlIlDataContextTypeTransformer.cs | 6 +++--- .../Transformers/AvaloniaXamlIlWellKnownTypes.cs | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs index c4d67deb4c..349143253e 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs @@ -24,7 +24,6 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers { AvaloniaXamlIlDataContextTypeMetadataNode inferredDataContextTypeNode = null; AvaloniaXamlIlDataContextTypeMetadataNode directiveDataContextTypeNode = null; - bool isDataTemplate = on.Type.GetClrType().Equals(context.GetAvaloniaTypes().DataTemplate); for (int i = 0; i < on.Children.Count; ++i) { @@ -57,7 +56,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers { inferredDataContextTypeNode = ParseDataContext(context, on, obj); } - else if(isDataTemplate + else if(context.GetAvaloniaTypes().DataTemplate.IsAssignableFrom(on.Type.GetClrType()) && pa.Property.Name == "DataType" && pa.Values[0] is XamlTypeExtensionNode dataTypeNode) { @@ -70,7 +69,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers // do more specialized inference if (directiveDataContextTypeNode is null) { - if (isDataTemplate && inferredDataContextTypeNode is null) + if (context.GetAvaloniaTypes().IDataTemplate.IsAssignableFrom(on.Type.GetClrType()) + && inferredDataContextTypeNode is null) { // Infer data type from collection binding on a control that displays items. var parentObject = context.ParentNodes().OfType().FirstOrDefault(); diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs index f4ca76c21c..3dec96dc43 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs @@ -41,6 +41,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers public IXamlType ResolveByNameExtension { get; } public IXamlType DataTemplate { get; } + public IXamlType IDataTemplate { get; } public IXamlType IItemsPresenterHost { get; } public IXamlType ItemsRepeater { get; } public IXamlType ReflectionBindingExtension { get; } @@ -98,6 +99,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers CompiledBindingExtension = cfg.TypeSystem.GetType("Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindingExtension"); ResolveByNameExtension = cfg.TypeSystem.GetType("Avalonia.Markup.Xaml.MarkupExtensions.ResolveByNameExtension"); DataTemplate = cfg.TypeSystem.GetType("Avalonia.Markup.Xaml.Templates.DataTemplate"); + IDataTemplate = cfg.TypeSystem.GetType("Avalonia.Controls.Templates.IDataTemplate"); IItemsPresenterHost = cfg.TypeSystem.GetType("Avalonia.Controls.Presenters.IItemsPresenterHost"); ItemsRepeater = cfg.TypeSystem.GetType("Avalonia.Controls.ItemsRepeater"); ReflectionBindingExtension = cfg.TypeSystem.GetType("Avalonia.Markup.Xaml.MarkupExtensions.ReflectionBindingExtension"); From 2df2943a27b86c42a38977b00b314011cd8644f3 Mon Sep 17 00:00:00 2001 From: Luis von der Eltz Date: Thu, 20 Aug 2020 10:51:41 +0200 Subject: [PATCH 03/12] !F Adding margin/padding --- .../Diagnostics/ViewModels/MainViewModel.cs | 16 ++++- .../ViewModels/TreePageViewModel.cs | 7 +- .../Diagnostics/Views/MainView.xaml | 9 +++ .../Diagnostics/Views/TreePageView.xaml.cs | 71 ++++++++++++++----- 4 files changed, 80 insertions(+), 23 deletions(-) diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs index 1d19e1a346..af087cfe6f 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs @@ -16,12 +16,13 @@ namespace Avalonia.Diagnostics.ViewModels private int _selectedTab; private string _focusedControl; private string _pointerOverElement; + private bool _shouldVisualizeMarginPadding = true; public MainViewModel(IControl root) { _root = root; - _logicalTree = new TreePageViewModel(LogicalTreeNode.Create(root)); - _visualTree = new TreePageViewModel(VisualTreeNode.Create(root)); + _logicalTree = new TreePageViewModel(this, LogicalTreeNode.Create(root)); + _visualTree = new TreePageViewModel(this, VisualTreeNode.Create(root)); _events = new EventsPageViewModel(root); UpdateFocusedControl(); @@ -39,6 +40,17 @@ namespace Avalonia.Diagnostics.ViewModels Console = new ConsoleViewModel(UpdateConsoleContext); } + public bool ShouldVisualizeMarginPadding + { + get => _shouldVisualizeMarginPadding; + set => RaiseAndSetIfChanged(ref _shouldVisualizeMarginPadding, value); + } + + public void ToggleVisualizeMarginPadding() + { + ShouldVisualizeMarginPadding = !ShouldVisualizeMarginPadding; + } + public ConsoleViewModel Console { get; } public ViewModelBase Content diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreePageViewModel.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreePageViewModel.cs index 38ac88a83c..92765dfd0d 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreePageViewModel.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreePageViewModel.cs @@ -10,8 +10,9 @@ namespace Avalonia.Diagnostics.ViewModels private ControlDetailsViewModel _details; private string _propertyFilter; - public TreePageViewModel(TreeNode[] nodes) + public TreePageViewModel(MainViewModel mainView, TreeNode[] nodes) { + MainView = mainView; Nodes = nodes; Selection = new SelectionModel { @@ -23,7 +24,9 @@ namespace Avalonia.Diagnostics.ViewModels { SelectedNode = (TreeNode)Selection.SelectedItem; }; - } + } + + public MainViewModel MainView { get; } public TreeNode[] Nodes { get; protected set; } diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/MainView.xaml b/src/Avalonia.Diagnostics/Diagnostics/Views/MainView.xaml index 663722acba..0165398718 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Views/MainView.xaml +++ b/src/Avalonia.Diagnostics/Diagnostics/Views/MainView.xaml @@ -16,6 +16,15 @@ + + + + + + + diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/TreePageView.xaml.cs b/src/Avalonia.Diagnostics/Diagnostics/Views/TreePageView.xaml.cs index 633d18ddd8..1b61986ce6 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Views/TreePageView.xaml.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/Views/TreePageView.xaml.cs @@ -1,7 +1,7 @@ +using System.Linq; using Avalonia.Controls; using Avalonia.Controls.Generators; using Avalonia.Controls.Primitives; -using Avalonia.Controls.Shapes; using Avalonia.Diagnostics.ViewModels; using Avalonia.Input; using Avalonia.Markup.Xaml; @@ -11,45 +11,78 @@ namespace Avalonia.Diagnostics.Views { internal class TreePageView : UserControl { - private Control _adorner; + private readonly Panel _adorner; + private AdornerLayer _currentLayer; private TreeView _tree; public TreePageView() { - this.InitializeComponent(); + InitializeComponent(); _tree.ItemContainerGenerator.Index.Materialized += TreeViewItemMaterialized; + + _adorner = new Panel + { + ClipToBounds = false, + Children = + { + //Padding frame + new Border { BorderBrush = new SolidColorBrush(Colors.Green, 0.5) }, + //Content frame + new Border { Background = new SolidColorBrush(Color.FromRgb(160, 197, 232), 0.5) }, + //Margin frame + new Border { BorderBrush = new SolidColorBrush(Colors.Yellow, 0.5) } + }, + }; } protected void AddAdorner(object sender, PointerEventArgs e) { var node = (TreeNode)((Control)sender).DataContext; - var layer = AdornerLayer.GetAdornerLayer(node.Visual); + var visual = (Visual)node.Visual; + + _currentLayer = AdornerLayer.GetAdornerLayer(visual); - if (layer != null) + if (_currentLayer == null || + _currentLayer.Children.Contains(_adorner)) { - if (_adorner != null) - { - ((Panel)_adorner.Parent).Children.Remove(_adorner); - _adorner = null; - } + return; + } - _adorner = new Rectangle - { - Fill = new SolidColorBrush(0x80a0c5e8), - [AdornerLayer.AdornedElementProperty] = node.Visual, - }; + _currentLayer.Children.Add(_adorner); + AdornerLayer.SetAdornedElement(_adorner, visual); + + var vm = (TreePageViewModel) DataContext; - layer.Children.Add(_adorner); + if (vm.MainView.ShouldVisualizeMarginPadding) + { + var paddingBorder = (Border)_adorner.Children[0]; + paddingBorder.BorderThickness = visual.GetValue(PaddingProperty); + + var contentBorder = (Border)_adorner.Children[1]; + contentBorder.Margin = visual.GetValue(PaddingProperty); + + var marginBorder = (Border)_adorner.Children[2]; + marginBorder.BorderThickness = visual.GetValue(MarginProperty); + marginBorder.Margin = InvertThickness(visual.GetValue(MarginProperty)); } } + private static Thickness InvertThickness(Thickness input) + { + return new Thickness(-input.Left, -input.Top, -input.Right, -input.Bottom); + } + protected void RemoveAdorner(object sender, PointerEventArgs e) { - if (_adorner != null) + foreach (var border in _adorner.Children.OfType()) { - ((Panel)_adorner.Parent).Children.Remove(_adorner); - _adorner = null; + border.Margin = default; + border.Padding = default; + border.BorderThickness = default; } + + _currentLayer?.Children.Remove(_adorner); + _currentLayer = null; } private void InitializeComponent() From 7727722cb3902c6cf59940f5232377478cf74f1a Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Thu, 20 Aug 2020 11:21:37 +0200 Subject: [PATCH 04/12] Make sure to always return a valid CharacterHit for next / previous CharacterHit --- .../Media/TextFormatting/TextLineImpl.cs | 16 +++++ .../Media/TextFormatting/TextLineTests.cs | 60 ++++++++++++++++++- 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs index 8b44e32c48..08d9107bb1 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs +++ b/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs @@ -181,6 +181,17 @@ namespace Avalonia.Media.TextFormatting return nextCharacterHit; } + if (characterHit.FirstCharacterIndex + characterHit.TrailingLength <= TextRange.Start + TextRange.Length) + { + return characterHit; // Can't move, we're after the last character + } + + var runIndex = GetRunIndexAtCodepointIndex(TextRange.End); + + var textRun = _textRuns[runIndex]; + + characterHit = textRun.GlyphRun.GetNextCaretCharacterHit(characterHit); + return characterHit; // Can't move, we're after the last character } @@ -192,6 +203,11 @@ namespace Avalonia.Media.TextFormatting return previousCharacterHit; } + if (characterHit.FirstCharacterIndex < TextRange.Start) + { + characterHit = new CharacterHit(TextRange.Start); + } + return characterHit; // Can't move, we're before the first character } diff --git a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs index 3655d78c9d..7abfe29f11 100644 --- a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs +++ b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Linq; using Avalonia.Media; using Avalonia.Media.TextFormatting; @@ -10,6 +9,65 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting { public class TextLineTests { + private static readonly string s_multiLineText = "012345678\r\r0123456789"; + + [Fact] + public void Should_Get_First_CharacterHit() + { + using (Start()) + { + var defaultProperties = new GenericTextRunProperties(Typeface.Default); + + var textSource = new SingleBufferTextSource(s_multiLineText, defaultProperties); + + var formatter = new TextFormatterImpl(); + + var currentIndex = 0; + + while (currentIndex < s_multiLineText.Length) + { + var textLine = + formatter.FormatLine(textSource, currentIndex, double.PositiveInfinity, + new GenericTextParagraphProperties(defaultProperties)); + + var firstCharacterHit = textLine.GetPreviousCaretCharacterHit(new CharacterHit(int.MinValue)); + + Assert.Equal(textLine.TextRange.Start, firstCharacterHit.FirstCharacterIndex); + + currentIndex += textLine.TextRange.Length; + } + } + } + + [Fact] + public void Should_Get_Last_CharacterHit() + { + using (Start()) + { + var defaultProperties = new GenericTextRunProperties(Typeface.Default); + + var textSource = new SingleBufferTextSource(s_multiLineText, defaultProperties); + + var formatter = new TextFormatterImpl(); + + var currentIndex = 0; + + while (currentIndex < s_multiLineText.Length) + { + var textLine = + formatter.FormatLine(textSource, currentIndex, double.PositiveInfinity, + new GenericTextParagraphProperties(defaultProperties)); + + var lastCharacterHit = textLine.GetNextCaretCharacterHit(new CharacterHit(int.MaxValue)); + + Assert.Equal(textLine.TextRange.Start + textLine.TextRange.Length, + lastCharacterHit.FirstCharacterIndex + lastCharacterHit.TrailingLength); + + currentIndex += textLine.TextRange.Length; + } + } + } + [InlineData("𐐷𐐷𐐷𐐷𐐷")] [InlineData("𐐷1234")] [Theory] From 5189509817724d49bb7baddcf7b03c8dae652af8 Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Thu, 20 Aug 2020 11:27:09 +0200 Subject: [PATCH 05/12] Fix #4521 --- src/Avalonia.Controls/Utils/BorderRenderHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/Utils/BorderRenderHelper.cs b/src/Avalonia.Controls/Utils/BorderRenderHelper.cs index 438cbc8b27..3128753781 100644 --- a/src/Avalonia.Controls/Utils/BorderRenderHelper.cs +++ b/src/Avalonia.Controls/Utils/BorderRenderHelper.cs @@ -141,7 +141,7 @@ namespace Avalonia.Controls.Utils var radiusY = keypoints.RightTop.Y - boundRect.TopRight.Y; if (radiusX != 0 || radiusY != 0) { - context.ArcTo(keypoints.RightTop, new Size(radiusY, radiusY), 0, false, SweepDirection.Clockwise); + context.ArcTo(keypoints.RightTop, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise); } // Right From ab58492b15248d12ca9701904cc9d00f27f2f3e6 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 20 Aug 2020 14:31:13 +0100 Subject: [PATCH 06/12] add failing unit test. --- .../TextBoxTests.cs | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs index f41938a9bb..fe25fa7346 100644 --- a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs @@ -562,6 +562,41 @@ namespace Avalonia.Controls.UnitTests } } + [Fact] + public void TextBox_CaretIndex_Persists_When_Focus_Lost() + { + using (UnitTestApplication.Start(FocusServices)) + { + var target1 = new TextBox + { + Template = CreateTemplate(), + Text = "1234" + }; + var target2 = new TextBox + { + Template = CreateTemplate(), + Text = "5678" + }; + var sp = new StackPanel(); + sp.Children.Add(target1); + sp.Children.Add(target2); + + target1.ApplyTemplate(); + target2.ApplyTemplate(); + + var root = new TestRoot { Child = sp }; + + target2.Focus(); + target2.CaretIndex = 2; + Assert.False(target1.IsFocused); + Assert.True(target2.IsFocused); + + target1.Focus(); + + Assert.Equal(2, target2.CaretIndex); + } + } + [Fact] public void TextBox_Reveal_Password_Reset_When_Lost_Focus() { From 24ea1f618f369a20e77332e7d7b50114bf24d6e4 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 20 Aug 2020 14:10:05 +0100 Subject: [PATCH 07/12] [TextBox] keep caret index when clearing selection. --- src/Avalonia.Controls/TextBox.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index 4e742b3b7b..5e2817af80 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -413,8 +413,7 @@ namespace Avalonia.Controls if (ContextMenu == null || !ContextMenu.IsOpen) { - SelectionStart = 0; - SelectionEnd = 0; + SelectionStart = SelectionEnd = CaretIndex; RevealPassword = false; } From d6f70744e6c930b0ecf6699b0cb4dcc8077f1041 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 20 Aug 2020 14:27:08 +0100 Subject: [PATCH 08/12] extract clear selection to method. --- src/Avalonia.Controls/TextBox.cs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index 5e2817af80..a81093bcc5 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -407,13 +407,18 @@ namespace Avalonia.Controls _presenter?.ShowCaret(); } + private void ClearSelection() + { + SelectionStart = SelectionEnd = CaretIndex; + } + protected override void OnLostFocus(RoutedEventArgs e) { base.OnLostFocus(e); if (ContextMenu == null || !ContextMenu.IsOpen) { - SelectionStart = SelectionEnd = CaretIndex; + ClearSelection(); RevealPassword = false; } @@ -443,7 +448,7 @@ namespace Avalonia.Controls text = Text ?? string.Empty; SetTextInternal(text.Substring(0, caretIndex) + input + text.Substring(caretIndex)); CaretIndex += input.Length; - SelectionStart = SelectionEnd = CaretIndex; + ClearSelection(); _undoRedoHelper.DiscardRedo(); } } @@ -661,7 +666,7 @@ namespace Avalonia.Controls SetTextInternal(text.Substring(0, caretIndex - removedCharacters) + text.Substring(caretIndex)); CaretIndex -= removedCharacters; - SelectionStart = SelectionEnd = CaretIndex; + ClearSelection(); } _undoRedoHelper.Snapshot(); @@ -734,7 +739,7 @@ namespace Avalonia.Controls } else if (movement) { - SelectionStart = SelectionEnd = CaretIndex; + ClearSelection(); } if (handled || movement) @@ -1041,7 +1046,8 @@ namespace Avalonia.Controls var end = Math.Max(selectionStart, selectionEnd); var text = Text; SetTextInternal(text.Substring(0, start) + text.Substring(end)); - SelectionStart = SelectionEnd = CaretIndex = start; + CaretIndex = start; + ClearSelection(); return true; } else @@ -1130,7 +1136,8 @@ namespace Avalonia.Controls set { Text = value.Text; - SelectionStart = SelectionEnd = CaretIndex = value.CaretPosition; + CaretIndex = value.CaretPosition; + ClearSelection(); } } } From 69f878df59600db097f189eabf7aae9bf77c8e89 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 20 Aug 2020 14:59:55 +0100 Subject: [PATCH 09/12] allow osx to run in vm where opengl init may fail. --- src/Avalonia.Native/AvaloniaNativePlatform.cs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.Native/AvaloniaNativePlatform.cs b/src/Avalonia.Native/AvaloniaNativePlatform.cs index cfd47d48de..804cf7f8ac 100644 --- a/src/Avalonia.Native/AvaloniaNativePlatform.cs +++ b/src/Avalonia.Native/AvaloniaNativePlatform.cs @@ -110,11 +110,20 @@ namespace Avalonia.Native .Bind().ToConstant(new SystemDialogs(_factory.CreateSystemDialogs())) .Bind().ToConstant(new PlatformHotkeyConfiguration(KeyModifiers.Meta)) .Bind().ToConstant(new MacOSMountedVolumeInfoProvider()) - .Bind().ToConstant(new AvaloniaNativeDragSource(_factory)) - ; + .Bind().ToConstant(new AvaloniaNativeDragSource(_factory)); + if (_options.UseGpu) - AvaloniaLocator.CurrentMutable.Bind() - .ToConstant(_glFeature = new GlPlatformFeature(_factory.ObtainGlDisplay())); + { + try + { + AvaloniaLocator.CurrentMutable.Bind() + .ToConstant(_glFeature = new GlPlatformFeature(_factory.ObtainGlDisplay())); + } + catch (Exception) + { + // ignored + } + } } public IWindowImpl CreateWindow() From 67381d0a9166c189439a133d5da6d72ce5c56b9d Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 20 Aug 2020 15:14:31 +0100 Subject: [PATCH 10/12] dont crash when window is closed and apis are still called. --- src/Avalonia.Native/WindowImplBase.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Native/WindowImplBase.cs b/src/Avalonia.Native/WindowImplBase.cs index 4b13666edd..08c5d51ea0 100644 --- a/src/Avalonia.Native/WindowImplBase.cs +++ b/src/Avalonia.Native/WindowImplBase.cs @@ -351,12 +351,12 @@ namespace Avalonia.Native public Point PointToClient(PixelPoint point) { - return _native.PointToClient(point.ToAvnPoint()).ToAvaloniaPoint(); + return _native?.PointToClient(point.ToAvnPoint()).ToAvaloniaPoint() ?? default; } public PixelPoint PointToScreen(Point point) { - return _native.PointToScreen(point.ToAvnPoint()).ToAvaloniaPixelPoint(); + return _native?.PointToScreen(point.ToAvnPoint()).ToAvaloniaPixelPoint() ?? default; } public void Hide() From 059e46f59244212676bb77f9a9634ff8c08db526 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 20 Aug 2020 19:38:03 +0100 Subject: [PATCH 11/12] make clear selection public. --- src/Avalonia.Controls/TextBox.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index a81093bcc5..d1d75d512e 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -407,7 +407,7 @@ namespace Avalonia.Controls _presenter?.ShowCaret(); } - private void ClearSelection() + public void ClearSelection() { SelectionStart = SelectionEnd = CaretIndex; } From abfa846e9dcc3af8daf96b3fe5adedb480e44a2b Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 20 Aug 2020 19:39:21 +0100 Subject: [PATCH 12/12] add comments and move public method above private and protected. --- src/Avalonia.Controls/TextBox.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index d1d75d512e..2506fd0624 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -369,6 +369,14 @@ namespace Avalonia.Controls get { return _newLine; } set { SetAndRaise(NewLineProperty, ref _newLine, value); } } + + /// + /// Clears the current selection, maintaining the + /// + public void ClearSelection() + { + SelectionStart = SelectionEnd = CaretIndex; + } protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { @@ -407,11 +415,6 @@ namespace Avalonia.Controls _presenter?.ShowCaret(); } - public void ClearSelection() - { - SelectionStart = SelectionEnd = CaretIndex; - } - protected override void OnLostFocus(RoutedEventArgs e) { base.OnLostFocus(e);