From 2bdb914dd1cd58d5aca75bb08d6e4ea96b29692b Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 9 Jul 2020 12:20:46 +0200 Subject: [PATCH 001/344] Show overlay layer when popup StaysOpen = false. We need to stop events getting to parent window. Pointer capture won't work because this now needs an input event in order to take pointer capture, and filtering events on the parent window causes tooltips to continue tooltips to get stuck. Best solution would seem to be using an overlay layer. --- .../Primitives/LightDismissOverlayLayer.cs | 10 ++++++++ src/Avalonia.Controls/Primitives/Popup.cs | 21 +++++++++++++--- .../Primitives/VisualLayerManager.cs | 25 ++++++++++++++++++- 3 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 src/Avalonia.Controls/Primitives/LightDismissOverlayLayer.cs diff --git a/src/Avalonia.Controls/Primitives/LightDismissOverlayLayer.cs b/src/Avalonia.Controls/Primitives/LightDismissOverlayLayer.cs new file mode 100644 index 0000000000..65a21a563a --- /dev/null +++ b/src/Avalonia.Controls/Primitives/LightDismissOverlayLayer.cs @@ -0,0 +1,10 @@ +using System.Linq; +using Avalonia.Rendering; +using Avalonia.VisualTree; + +namespace Avalonia.Controls.Primitives +{ + public class LightDismissOverlayLayer : Border + { + } +} diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs index 1fcf8d61bc..01ae6fbf43 100644 --- a/src/Avalonia.Controls/Primitives/Popup.cs +++ b/src/Avalonia.Controls/Primitives/Popup.cs @@ -369,8 +369,6 @@ namespace Avalonia.Controls.Primitives } } - DeferCleanup(topLevel.AddDisposableHandler(PointerPressedEvent, PointerPressedOutside, RoutingStrategies.Tunnel)); - DeferCleanup(InputManager.Instance?.Process.Subscribe(ListenForNonClientClick)); var cleanupPopup = Disposable.Create((popupHost, handlerCleanup), state => @@ -384,6 +382,23 @@ namespace Avalonia.Controls.Primitives state.popupHost.Dispose(); }); + if (!StaysOpen) + { + var layerManager = placementTarget.FindAncestorOfType(); + var dismissLayer = layerManager?.LightDismissOverlayLayer; + + if (dismissLayer != null) + { + dismissLayer.IsVisible = true; + DeferCleanup(Disposable.Create(() => dismissLayer.IsVisible = false)); + DeferCleanup(SubscribeToEventHandler>( + dismissLayer, + PointerPressedDismissOverlay, + (x, handler) => x.PointerPressed += handler, + (x, handler) => x.PointerPressed -= handler)); + } + } + _openState = new PopupOpenState(topLevel, popupHost, cleanupPopup); WindowManagerAddShadowHintChanged(popupHost, WindowManagerAddShadowHint); @@ -504,7 +519,7 @@ namespace Avalonia.Controls.Primitives } } - private void PointerPressedOutside(object sender, PointerPressedEventArgs e) + private void PointerPressedDismissOverlay(object sender, PointerPressedEventArgs e) { if (!StaysOpen && e.Source is IVisual v && !IsChildOrThis(v)) { diff --git a/src/Avalonia.Controls/Primitives/VisualLayerManager.cs b/src/Avalonia.Controls/Primitives/VisualLayerManager.cs index 3084d7fa72..a4e230e2f4 100644 --- a/src/Avalonia.Controls/Primitives/VisualLayerManager.cs +++ b/src/Avalonia.Controls/Primitives/VisualLayerManager.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using Avalonia.LogicalTree; +using Avalonia.Media; namespace Avalonia.Controls.Primitives { @@ -7,7 +8,8 @@ namespace Avalonia.Controls.Primitives { private const int AdornerZIndex = int.MaxValue - 100; private const int ChromeZIndex = int.MaxValue - 99; - private const int OverlayZIndex = int.MaxValue - 98; + private const int LightDismissOverlayZIndex = int.MaxValue - 98; + private const int OverlayZIndex = int.MaxValue - 97; private ILogicalRoot _logicalRoot; private readonly List _layers = new List(); @@ -50,6 +52,27 @@ namespace Avalonia.Controls.Primitives } } + public LightDismissOverlayLayer LightDismissOverlayLayer + { + get + { + if (IsPopup) + return null; + var rv = FindLayer(); + if (rv == null) + { + rv = new LightDismissOverlayLayer + { + Background = Brushes.Transparent, + IsVisible = false + }; + + AddLayer(rv, LightDismissOverlayZIndex); + } + return rv; + } + } + T FindLayer() where T : class { foreach (var layer in _layers) From 529b279549f6570745565b0c2b3d4eabf4dad5e8 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 9 Jul 2020 22:02:37 +0200 Subject: [PATCH 002/344] Fix failing popup tests. --- .../Primitives/LightDismissOverlayLayer.cs | 33 ++++++++++++++++++- src/Avalonia.Controls/Primitives/Popup.cs | 3 +- .../Primitives/PopupTests.cs | 3 +- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.Controls/Primitives/LightDismissOverlayLayer.cs b/src/Avalonia.Controls/Primitives/LightDismissOverlayLayer.cs index 65a21a563a..ede9a9b635 100644 --- a/src/Avalonia.Controls/Primitives/LightDismissOverlayLayer.cs +++ b/src/Avalonia.Controls/Primitives/LightDismissOverlayLayer.cs @@ -1,10 +1,41 @@ +using System; using System.Linq; -using Avalonia.Rendering; +using Avalonia.Controls.Templates; +using Avalonia.Styling; using Avalonia.VisualTree; +#nullable enable + namespace Avalonia.Controls.Primitives { + /// + /// A layer that is used to dismiss a when the user clicks outside. + /// public class LightDismissOverlayLayer : Border { + /// + /// Returns the light dismiss overlay for a specified visual. + /// + /// The visual. + /// The light dismiss overlay, or null if none found. + public static LightDismissOverlayLayer? GetLightDismissOverlayLayer(IVisual visual) + { + visual = visual ?? throw new ArgumentNullException(nameof(visual)); + + VisualLayerManager? manager; + + if (visual is TopLevel topLevel) + { + manager = topLevel.GetTemplateChildren() + .OfType() + .FirstOrDefault(); + } + else + { + manager = visual.FindAncestorOfType(); + } + + return manager?.LightDismissOverlayLayer; + } } } diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs index 01ae6fbf43..00bb026d0f 100644 --- a/src/Avalonia.Controls/Primitives/Popup.cs +++ b/src/Avalonia.Controls/Primitives/Popup.cs @@ -384,8 +384,7 @@ namespace Avalonia.Controls.Primitives if (!StaysOpen) { - var layerManager = placementTarget.FindAncestorOfType(); - var dismissLayer = layerManager?.LightDismissOverlayLayer; + var dismissLayer = LightDismissOverlayLayer.GetLightDismissOverlayLayer(placementTarget); if (dismissLayer != null) { diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs index fd06ba295b..5519c11582 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs @@ -392,7 +392,8 @@ namespace Avalonia.Controls.UnitTests.Primitives ++raised; }; - window.RaiseEvent(press); + var lightDismissLayer = window.FindDescendantOfType().LightDismissOverlayLayer; + lightDismissLayer.RaiseEvent(press); Assert.Equal(1, raised); } From b2a7339b4bc6246467b3b55f0eb5ff98e23604dd Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 10 Jul 2020 00:10:18 +0200 Subject: [PATCH 003/344] Added Popup.IsLightDismissEnabled property. And deprecate `StaysOpen` in favor of this property. --- src/Avalonia.Controls/ContextMenu.cs | 2 +- src/Avalonia.Controls/Primitives/Popup.cs | 41 ++++++++++++++----- .../Primitives/PopupClosedEventArgs.cs | 2 +- .../AutoCompleteBox.xaml | 2 +- src/Avalonia.Themes.Default/ComboBox.xaml | 2 +- src/Avalonia.Themes.Default/MenuItem.xaml | 4 +- .../AutoCompleteBox.xaml | 2 +- .../CalendarDatePicker.xaml | 2 +- src/Avalonia.Themes.Fluent/ComboBox.xaml | 2 +- src/Avalonia.Themes.Fluent/DatePicker.xaml | 2 +- src/Avalonia.Themes.Fluent/MenuItem.xaml | 5 +-- src/Avalonia.Themes.Fluent/TimePicker.xaml | 2 +- .../Primitives/PopupTests.cs | 6 +-- 13 files changed, 45 insertions(+), 29 deletions(-) diff --git a/src/Avalonia.Controls/ContextMenu.cs b/src/Avalonia.Controls/ContextMenu.cs index 5929dd39d4..7720011d5e 100644 --- a/src/Avalonia.Controls/ContextMenu.cs +++ b/src/Avalonia.Controls/ContextMenu.cs @@ -265,7 +265,7 @@ namespace Avalonia.Controls PlacementMode = PlacementMode, PlacementRect = PlacementRect, PlacementTarget = PlacementTarget ?? control, - StaysOpen = false + IsLightDismissEnabled = true, }; _popup.Opened += PopupOpened; diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs index 00bb026d0f..7272a565d9 100644 --- a/src/Avalonia.Controls/Primitives/Popup.cs +++ b/src/Avalonia.Controls/Primitives/Popup.cs @@ -92,6 +92,12 @@ namespace Avalonia.Controls.Primitives public static readonly StyledProperty HorizontalOffsetProperty = AvaloniaProperty.Register(nameof(HorizontalOffset)); + /// + /// Defines the property. + /// + public static readonly StyledProperty IsLightDismissEnabledProperty = + AvaloniaProperty.Register(nameof(IsLightDismissEnabled)); + /// /// Defines the property. /// @@ -101,8 +107,13 @@ namespace Avalonia.Controls.Primitives /// /// Defines the property. /// - public static readonly StyledProperty StaysOpenProperty = - AvaloniaProperty.Register(nameof(StaysOpen), true); + [Obsolete("Use IsLightDismissEnabledProperty")] + public static readonly DirectProperty StaysOpenProperty = + AvaloniaProperty.RegisterDirect( + nameof(StaysOpen), + o => o.StaysOpen, + (o, v) => o.StaysOpen = v, + true); /// /// Defines the property. @@ -165,6 +176,15 @@ namespace Avalonia.Controls.Primitives set; } + /// + /// Gets or sets a value that determines how the can be dismissed. + /// + public bool IsLightDismissEnabled + { + get => GetValue(IsLightDismissEnabledProperty); + set => SetValue(IsLightDismissEnabledProperty, value); + } + /// /// Gets or sets a value indicating whether the popup is currently open. /// @@ -268,10 +288,11 @@ namespace Avalonia.Controls.Primitives /// Gets or sets a value indicating whether the popup should stay open when the popup is /// pressed or loses focus. /// + [Obsolete("Use IsLightDismissEnabled")] public bool StaysOpen { - get { return GetValue(StaysOpenProperty); } - set { SetValue(StaysOpenProperty, value); } + get => !IsLightDismissEnabled; + set => IsLightDismissEnabled = !value; } /// @@ -382,7 +403,7 @@ namespace Avalonia.Controls.Primitives state.popupHost.Dispose(); }); - if (!StaysOpen) + if (IsLightDismissEnabled) { var dismissLayer = LightDismissOverlayLayer.GetLightDismissOverlayLayer(placementTarget); @@ -512,7 +533,7 @@ namespace Avalonia.Controls.Primitives { var mouse = e as RawPointerEventArgs; - if (!StaysOpen && mouse?.Type == RawPointerEventType.NonClientLeftButtonDown) + if (IsLightDismissEnabled && mouse?.Type == RawPointerEventType.NonClientLeftButtonDown) { CloseCore(e); } @@ -520,7 +541,7 @@ namespace Avalonia.Controls.Primitives private void PointerPressedDismissOverlay(object sender, PointerPressedEventArgs e) { - if (!StaysOpen && e.Source is IVisual v && !IsChildOrThis(v)) + if (IsLightDismissEnabled && e.Source is IVisual v && !IsChildOrThis(v)) { CloseCore(e); } @@ -616,7 +637,7 @@ namespace Avalonia.Controls.Primitives private void WindowDeactivated(object sender, EventArgs e) { - if (!StaysOpen) + if (IsLightDismissEnabled) { Close(); } @@ -624,7 +645,7 @@ namespace Avalonia.Controls.Primitives private void ParentClosed(object sender, EventArgs e) { - if (!StaysOpen) + if (IsLightDismissEnabled) { Close(); } @@ -632,7 +653,7 @@ namespace Avalonia.Controls.Primitives private void WindowLostFocus() { - if(!StaysOpen) + if(IsLightDismissEnabled) Close(); } diff --git a/src/Avalonia.Controls/Primitives/PopupClosedEventArgs.cs b/src/Avalonia.Controls/Primitives/PopupClosedEventArgs.cs index c51543438c..db554b3c82 100644 --- a/src/Avalonia.Controls/Primitives/PopupClosedEventArgs.cs +++ b/src/Avalonia.Controls/Primitives/PopupClosedEventArgs.cs @@ -23,7 +23,7 @@ namespace Avalonia.Controls.Primitives /// Gets the event that closed the popup, if any. /// /// - /// If is false, then this property will hold details of the + /// If is true, then this property will hold details of the /// interaction that caused the popup to close if the close was caused by e.g. a pointer press /// outside the popup. It can be used to mark the event as handled if the event should not /// be propagated. diff --git a/src/Avalonia.Themes.Default/AutoCompleteBox.xaml b/src/Avalonia.Themes.Default/AutoCompleteBox.xaml index 788b60892b..66d0f17ede 100644 --- a/src/Avalonia.Themes.Default/AutoCompleteBox.xaml +++ b/src/Avalonia.Themes.Default/AutoCompleteBox.xaml @@ -19,7 +19,7 @@ MinWidth="{Binding Bounds.Width, RelativeSource={RelativeSource TemplatedParent}}" MaxHeight="{TemplateBinding MaxDropDownHeight}" PlacementTarget="{TemplateBinding}" - StaysOpen="False"> + IsLightDismissEnabled="True"> + IsLightDismissEnabled="True"> diff --git a/src/Avalonia.Themes.Default/MenuItem.xaml b/src/Avalonia.Themes.Default/MenuItem.xaml index d7f367c591..0eb87166b2 100644 --- a/src/Avalonia.Themes.Default/MenuItem.xaml +++ b/src/Avalonia.Themes.Default/MenuItem.xaml @@ -59,7 +59,6 @@ Grid.Column="4"/> + IsOpen="{TemplateBinding IsSubMenuOpen, Mode=TwoWay}"> diff --git a/src/Avalonia.Themes.Fluent/AutoCompleteBox.xaml b/src/Avalonia.Themes.Fluent/AutoCompleteBox.xaml index 0d5d733cd9..6d83674c43 100644 --- a/src/Avalonia.Themes.Fluent/AutoCompleteBox.xaml +++ b/src/Avalonia.Themes.Fluent/AutoCompleteBox.xaml @@ -47,7 +47,7 @@ WindowManagerAddShadowHint="False" MinWidth="{Binding Bounds.Width, RelativeSource={RelativeSource TemplatedParent}}" MaxHeight="{TemplateBinding MaxDropDownHeight}" - StaysOpen="False" + IsLightDismissEnabled="True" PlacementTarget="{TemplateBinding}"> + IsLightDismissEnabled="True"> diff --git a/src/Avalonia.Themes.Fluent/ComboBox.xaml b/src/Avalonia.Themes.Fluent/ComboBox.xaml index 2788344842..2d43a2afe5 100644 --- a/src/Avalonia.Themes.Fluent/ComboBox.xaml +++ b/src/Avalonia.Themes.Fluent/ComboBox.xaml @@ -123,7 +123,7 @@ MinWidth="{Binding Bounds.Width, RelativeSource={RelativeSource TemplatedParent}}" MaxHeight="{TemplateBinding MaxDropDownHeight}" PlacementTarget="{TemplateBinding}" - StaysOpen="False"> + IsLightDismissEnabled="True"> diff --git a/src/Avalonia.Themes.Fluent/MenuItem.xaml b/src/Avalonia.Themes.Fluent/MenuItem.xaml index fbb994e90c..f861c456e9 100644 --- a/src/Avalonia.Themes.Fluent/MenuItem.xaml +++ b/src/Avalonia.Themes.Fluent/MenuItem.xaml @@ -108,7 +108,6 @@ + IsOpen="{TemplateBinding IsSubMenuOpen, Mode=TwoWay}"> diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs index 5519c11582..1d5b39cc14 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs @@ -349,7 +349,7 @@ namespace Avalonia.Controls.UnitTests.Primitives } [Fact] - public void StaysOpen_False_Should_Not_Handle_Closing_Click() + public void LightDismiss_Should_Not_Handle_Closing_Click() { using (CreateServices()) { @@ -357,7 +357,7 @@ namespace Avalonia.Controls.UnitTests.Primitives var target = new Popup() { PlacementTarget = window , - StaysOpen = false, + IsLightDismissEnabled = true, }; target.Open(); @@ -378,7 +378,7 @@ namespace Avalonia.Controls.UnitTests.Primitives var target = new Popup() { PlacementTarget = window, - StaysOpen = false, + IsLightDismissEnabled = true, }; target.Open(); From c45436dff124117a01b591262e9b80441a5b1a91 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 10 Jul 2020 09:49:59 +0200 Subject: [PATCH 004/344] Added Popup.OverlayDismissEventPassThrough. To control whether dismiss events are passed through from the overlay layer to the underlying window content. --- src/Avalonia.Controls/AutoCompleteBox.cs | 7 +-- .../Calendar/CalendarDatePicker.cs | 7 +-- src/Avalonia.Controls/ComboBox.cs | 22 +------ src/Avalonia.Controls/ContextMenu.cs | 1 + src/Avalonia.Controls/Primitives/Popup.cs | 59 ++++++++++++++++--- .../Primitives/PopupClosedEventArgs.cs | 33 ----------- src/Avalonia.Input/InputExtensions.cs | 29 ++++++++- .../Primitives/PopupTests.cs | 49 ++++++--------- .../MockWindowingPlatform.cs | 4 ++ 9 files changed, 103 insertions(+), 108 deletions(-) delete mode 100644 src/Avalonia.Controls/Primitives/PopupClosedEventArgs.cs diff --git a/src/Avalonia.Controls/AutoCompleteBox.cs b/src/Avalonia.Controls/AutoCompleteBox.cs index 31101dc0f1..c164f282e8 100644 --- a/src/Avalonia.Controls/AutoCompleteBox.cs +++ b/src/Avalonia.Controls/AutoCompleteBox.cs @@ -1647,7 +1647,7 @@ namespace Avalonia.Controls /// /// The source object. /// The event data. - private void DropDownPopup_Closed(object sender, PopupClosedEventArgs e) + private void DropDownPopup_Closed(object sender, EventArgs e) { // Force the drop down dependency property to be false. if (IsDropDownOpen) @@ -1655,11 +1655,6 @@ namespace Avalonia.Controls IsDropDownOpen = false; } - if (e.CloseEvent is PointerEventArgs pointerEvent) - { - pointerEvent.Handled = true; - } - // Fire the DropDownClosed event if (_popupHasOpened) { diff --git a/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs b/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs index b987f065be..046b55d49a 100644 --- a/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs +++ b/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs @@ -889,17 +889,12 @@ namespace Avalonia.Controls _ignoreButtonClick = false; } } - private void PopUp_Closed(object sender, PopupClosedEventArgs e) + private void PopUp_Closed(object sender, EventArgs e) { IsDropDownOpen = false; if(!_isPopupClosing) { - if (e.CloseEvent is PointerEventArgs pointerEvent) - { - pointerEvent.Handled = true; - } - _isPopupClosing = true; Threading.Dispatcher.UIThread.InvokeAsync(() => _isPopupClosing = false); } diff --git a/src/Avalonia.Controls/ComboBox.cs b/src/Avalonia.Controls/ComboBox.cs index 75a0e41e7b..27313b0b4c 100644 --- a/src/Avalonia.Controls/ComboBox.cs +++ b/src/Avalonia.Controls/ComboBox.cs @@ -290,24 +290,6 @@ namespace Avalonia.Controls _popup = e.NameScope.Get("PART_Popup"); _popup.Opened += PopupOpened; - _popup.Closed += PopupClosed; - } - - /// - /// Called when the ComboBox popup is closed, with the - /// that caused the popup to close. - /// - /// The event args. - /// - /// This method can be overridden to control whether the event that caused the popup to close - /// is swallowed or passed through. - /// - protected virtual void PopupClosedOverride(PopupClosedEventArgs e) - { - if (e.CloseEvent is PointerEventArgs pointerEvent) - { - pointerEvent.Handled = true; - } } internal void ItemFocused(ComboBoxItem dropDownItem) @@ -318,13 +300,11 @@ namespace Avalonia.Controls } } - private void PopupClosed(object sender, PopupClosedEventArgs e) + private void PopupClosed(object sender, EventArgs e) { _subscriptionsOnOpen?.Dispose(); _subscriptionsOnOpen = null; - PopupClosedOverride(e); - if (CanFocus(this)) { Focus(); diff --git a/src/Avalonia.Controls/ContextMenu.cs b/src/Avalonia.Controls/ContextMenu.cs index 7720011d5e..b4e4dd5071 100644 --- a/src/Avalonia.Controls/ContextMenu.cs +++ b/src/Avalonia.Controls/ContextMenu.cs @@ -266,6 +266,7 @@ namespace Avalonia.Controls PlacementRect = PlacementRect, PlacementTarget = PlacementTarget ?? control, IsLightDismissEnabled = true, + OverlayDismissEventPassThrough = true, }; _popup.Opened += PopupOpened; diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs index 7272a565d9..c97d90baed 100644 --- a/src/Avalonia.Controls/Primitives/Popup.cs +++ b/src/Avalonia.Controls/Primitives/Popup.cs @@ -1,12 +1,10 @@ using System; -using System.Diagnostics; using System.Linq; using System.Reactive.Disposables; using Avalonia.Controls.Presenters; using Avalonia.Controls.Primitives.PopupPositioning; using Avalonia.Input; using Avalonia.Input.Raw; -using Avalonia.Interactivity; using Avalonia.LogicalTree; using Avalonia.Metadata; using Avalonia.Platform; @@ -86,6 +84,9 @@ namespace Avalonia.Controls.Primitives AvaloniaProperty.Register(nameof(ObeyScreenEdges), true); #pragma warning restore 618 + public static readonly StyledProperty OverlayDismissEventPassThroughProperty = + AvaloniaProperty.Register(nameof(OverlayDismissEventPassThrough)); + /// /// Defines the property. /// @@ -138,7 +139,7 @@ namespace Avalonia.Controls.Primitives /// /// Raised when the popup closes. /// - public event EventHandler? Closed; + public event EventHandler? Closed; /// /// Raised when the popup opens. @@ -179,6 +180,9 @@ namespace Avalonia.Controls.Primitives /// /// Gets or sets a value that determines how the can be dismissed. /// + /// + /// Light dismiss is when the user taps on any area other than the popup. + /// public bool IsLightDismissEnabled { get => GetValue(IsLightDismissEnabledProperty); @@ -266,6 +270,22 @@ namespace Avalonia.Controls.Primitives set => SetValue(ObeyScreenEdgesProperty, value); } + /// + /// Gets or sets a value indicating whether the event that closes the popup is passed + /// through to the parent window. + /// + /// + /// When is set to true, clicks outside the the popup + /// cause the popup to close. When is set to + /// false, these clicks will be handled by the popup and not be registered by the parent + /// window. When set to true, the events will be passed through to the parent window. + /// + public bool OverlayDismissEventPassThrough + { + get => GetValue(OverlayDismissEventPassThroughProperty); + set => SetValue(OverlayDismissEventPassThroughProperty, value); + } + /// /// Gets or sets the Horizontal offset of the popup in relation to the . /// @@ -384,7 +404,7 @@ namespace Avalonia.Controls.Primitives if (parentPopupRoot?.Parent is Popup popup) { - DeferCleanup(SubscribeToEventHandler>(popup, ParentClosed, + DeferCleanup(SubscribeToEventHandler>(popup, ParentClosed, (x, handler) => x.Closed += handler, (x, handler) => x.Closed -= handler)); } @@ -436,7 +456,7 @@ namespace Avalonia.Controls.Primitives /// /// Closes the popup. /// - public void Close() => CloseCore(null); + public void Close() => CloseCore(); /// /// Measures the control. @@ -506,7 +526,7 @@ namespace Avalonia.Controls.Primitives } } - private void CloseCore(EventArgs? closeEvent) + private void CloseCore() { if (_openState is null) { @@ -526,7 +546,7 @@ namespace Avalonia.Controls.Primitives IsOpen = false; } - Closed?.Invoke(this, new PopupClosedEventArgs(closeEvent)); + Closed?.Invoke(this, EventArgs.Empty); } private void ListenForNonClientClick(RawInputEventArgs e) @@ -535,7 +555,7 @@ namespace Avalonia.Controls.Primitives if (IsLightDismissEnabled && mouse?.Type == RawPointerEventType.NonClientLeftButtonDown) { - CloseCore(e); + CloseCore(); } } @@ -543,7 +563,28 @@ namespace Avalonia.Controls.Primitives { if (IsLightDismissEnabled && e.Source is IVisual v && !IsChildOrThis(v)) { - CloseCore(e); + CloseCore(); + + if (OverlayDismissEventPassThrough) + { + PassThroughEvent(e); + } + } + } + + private void PassThroughEvent(PointerPressedEventArgs e) + { + if (e.Source is LightDismissOverlayLayer layer && + layer.GetVisualRoot() is IInputElement root) + { + var p = e.GetCurrentPoint(root); + var hit = root.InputHitTest(p.Position, x => x != layer); + + if (hit != null) + { + hit.RaiseEvent(e); + e.Handled = true; + } } } diff --git a/src/Avalonia.Controls/Primitives/PopupClosedEventArgs.cs b/src/Avalonia.Controls/Primitives/PopupClosedEventArgs.cs deleted file mode 100644 index db554b3c82..0000000000 --- a/src/Avalonia.Controls/Primitives/PopupClosedEventArgs.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using Avalonia.Interactivity; - -#nullable enable - -namespace Avalonia.Controls.Primitives -{ - /// - /// Holds data for the event. - /// - public class PopupClosedEventArgs : EventArgs - { - /// - /// Initializes a new instance of the class. - /// - /// - public PopupClosedEventArgs(EventArgs? closeEvent) - { - CloseEvent = closeEvent; - } - - /// - /// Gets the event that closed the popup, if any. - /// - /// - /// If is true, then this property will hold details of the - /// interaction that caused the popup to close if the close was caused by e.g. a pointer press - /// outside the popup. It can be used to mark the event as handled if the event should not - /// be propagated. - /// - public EventArgs? CloseEvent { get; } - } -} diff --git a/src/Avalonia.Input/InputExtensions.cs b/src/Avalonia.Input/InputExtensions.cs index 4babe711f2..cbe36583e6 100644 --- a/src/Avalonia.Input/InputExtensions.cs +++ b/src/Avalonia.Input/InputExtensions.cs @@ -3,6 +3,8 @@ using System.Collections.Generic; using System.Linq; using Avalonia.VisualTree; +#nullable enable + namespace Avalonia.Input { /// @@ -22,7 +24,7 @@ namespace Avalonia.Input /// public static IEnumerable GetInputElementsAt(this IInputElement element, Point p) { - Contract.Requires(element != null); + element = element ?? throw new ArgumentNullException(nameof(element)); return element.GetVisualsAt(p, s_hitTestDelegate).Cast(); } @@ -33,13 +35,34 @@ namespace Avalonia.Input /// The element to test. /// The point on . /// The topmost at the specified position. - public static IInputElement InputHitTest(this IInputElement element, Point p) + public static IInputElement? InputHitTest(this IInputElement element, Point p) { - Contract.Requires(element != null); + element = element ?? throw new ArgumentNullException(nameof(element)); return element.GetVisualAt(p, s_hitTestDelegate) as IInputElement; } + /// + /// Returns the topmost active input element at a point on an . + /// + /// The element to test. + /// The point on . + /// + /// A filter predicate. If the predicate returns false then the visual and all its + /// children will be excluded from the results. + /// + /// The topmost at the specified position. + public static IInputElement? InputHitTest( + this IInputElement element, + Point p, + Func filter) + { + element = element ?? throw new ArgumentNullException(nameof(element)); + filter = filter ?? throw new ArgumentNullException(nameof(filter)); + + return element.GetVisualAt(p, x => s_hitTestDelegate(x) && filter(x)) as IInputElement; + } + private static bool IsHitTestVisible(IVisual visual) { var element = visual as IInputElement; diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs index 1d5b39cc14..422ade2f90 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs @@ -349,53 +349,42 @@ namespace Avalonia.Controls.UnitTests.Primitives } [Fact] - public void LightDismiss_Should_Not_Handle_Closing_Click() + public void OverlayDismissEventPassThrough_Should_Pass_Event_To_Window_Contents() { using (CreateServices()) { var window = PreparedWindow(); + var rendererMock = Mock.Get(window.Renderer); var target = new Popup() { PlacementTarget = window , IsLightDismissEnabled = true, + OverlayDismissEventPassThrough = true, }; - target.Open(); - - var e = CreatePointerPressedEventArgs(window); - window.RaiseEvent(e); + var raised = 0; + var border = new Border(); + window.Content = border; - Assert.False(e.Handled); - } - } + rendererMock.Setup(x => + x.HitTestFirst(new Point(10, 15), window, It.IsAny>())) + .Returns(border); - [Fact] - public void Should_Pass_Closing_Click_To_Closed_Event() - { - using (CreateServices()) - { - var window = PreparedWindow(); - var target = new Popup() + border.PointerPressed += (s, e) => { - PlacementTarget = window, - IsLightDismissEnabled = true, + Assert.Same(border, e.Source); + ++raised; }; target.Open(); + Assert.True(target.IsOpen); - var press = CreatePointerPressedEventArgs(window); - var raised = 0; - - target.Closed += (s, e) => - { - Assert.Same(press, e.CloseEvent); - ++raised; - }; - - var lightDismissLayer = window.FindDescendantOfType().LightDismissOverlayLayer; - lightDismissLayer.RaiseEvent(press); + var e = CreatePointerPressedEventArgs(window, new Point(10, 15)); + var overlay = LightDismissOverlayLayer.GetLightDismissOverlayLayer(window); + overlay.RaiseEvent(e); Assert.Equal(1, raised); + Assert.False(target.IsOpen); } } @@ -411,14 +400,14 @@ namespace Avalonia.Controls.UnitTests.Primitives }))); } - private PointerPressedEventArgs CreatePointerPressedEventArgs(Window source) + private PointerPressedEventArgs CreatePointerPressedEventArgs(Window source, Point p) { var pointer = new Pointer(Pointer.GetNextFreeId(), PointerType.Mouse, true); return new PointerPressedEventArgs( source, pointer, source, - default, + p, 0, new PointerPointProperties(RawInputModifiers.None, PointerUpdateKind.LeftButtonPressed), KeyModifiers.None); diff --git a/tests/Avalonia.UnitTests/MockWindowingPlatform.cs b/tests/Avalonia.UnitTests/MockWindowingPlatform.cs index 48a333dc54..9b77fbb009 100644 --- a/tests/Avalonia.UnitTests/MockWindowingPlatform.cs +++ b/tests/Avalonia.UnitTests/MockWindowingPlatform.cs @@ -3,6 +3,7 @@ using Avalonia.Controls.Primitives.PopupPositioning; using Avalonia.Input; using Moq; using Avalonia.Platform; +using Avalonia.Rendering; namespace Avalonia.UnitTests { @@ -39,6 +40,9 @@ namespace Avalonia.UnitTests return CreatePopupMock(windowImpl.Object).Object; }); + windowImpl.Setup(x => x.CreateRenderer(It.IsAny())) + .Returns(Mock.Of()); + windowImpl.Setup(x => x.Dispose()).Callback(() => { windowImpl.Object.Closed?.Invoke(); From 714b0740db18387d055886360c37b9bf40fcf6dd Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 10 Jul 2020 13:14:22 +0200 Subject: [PATCH 005/344] Make leak tests pass again. --- .../Primitives/PopupTests.cs | 13 ++++++++++--- tests/Avalonia.UnitTests/MockWindowingPlatform.cs | 3 --- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs index 422ade2f90..d9176ca55d 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs @@ -14,6 +14,7 @@ using Avalonia.UnitTests; using Avalonia.VisualTree; using Xunit; using Avalonia.Input; +using Avalonia.Rendering; namespace Avalonia.Controls.UnitTests.Primitives { @@ -353,8 +354,14 @@ namespace Avalonia.Controls.UnitTests.Primitives { using (CreateServices()) { - var window = PreparedWindow(); - var rendererMock = Mock.Get(window.Renderer); + var renderer = new Mock(); + var platform = AvaloniaLocator.Current.GetService(); + var windowImpl = Mock.Get(platform.CreateWindow()); + windowImpl.Setup(x => x.CreateRenderer(It.IsAny())).Returns(renderer.Object); + + var window = new Window(windowImpl.Object); + window.ApplyTemplate(); + var target = new Popup() { PlacementTarget = window , @@ -366,7 +373,7 @@ namespace Avalonia.Controls.UnitTests.Primitives var border = new Border(); window.Content = border; - rendererMock.Setup(x => + renderer.Setup(x => x.HitTestFirst(new Point(10, 15), window, It.IsAny>())) .Returns(border); diff --git a/tests/Avalonia.UnitTests/MockWindowingPlatform.cs b/tests/Avalonia.UnitTests/MockWindowingPlatform.cs index 9b77fbb009..72f8ab9fd0 100644 --- a/tests/Avalonia.UnitTests/MockWindowingPlatform.cs +++ b/tests/Avalonia.UnitTests/MockWindowingPlatform.cs @@ -40,9 +40,6 @@ namespace Avalonia.UnitTests return CreatePopupMock(windowImpl.Object).Object; }); - windowImpl.Setup(x => x.CreateRenderer(It.IsAny())) - .Returns(Mock.Of()); - windowImpl.Setup(x => x.Dispose()).Callback(() => { windowImpl.Object.Closed?.Invoke(); From dd563805cde3e864c08a89b0c04a8dc54cf53238 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 10 Jul 2020 13:24:41 +0200 Subject: [PATCH 006/344] Nullable enable menu-related classes. --- src/Avalonia.Controls/IMenuElement.cs | 4 +++- src/Avalonia.Controls/IMenuItem.cs | 6 ++++-- src/Avalonia.Controls/Menu.cs | 2 ++ src/Avalonia.Controls/MenuBase.cs | 8 ++++---- src/Avalonia.Controls/MenuItem.cs | 20 ++++++++++--------- .../Platform/DefaultMenuInteractionHandler.cs | 7 ++++--- 6 files changed, 28 insertions(+), 19 deletions(-) diff --git a/src/Avalonia.Controls/IMenuElement.cs b/src/Avalonia.Controls/IMenuElement.cs index ee9d0fd6b6..426f265084 100644 --- a/src/Avalonia.Controls/IMenuElement.cs +++ b/src/Avalonia.Controls/IMenuElement.cs @@ -1,6 +1,8 @@ using System.Collections.Generic; using Avalonia.Input; +#nullable enable + namespace Avalonia.Controls { /// @@ -11,7 +13,7 @@ namespace Avalonia.Controls /// /// Gets or sets the currently selected submenu item. /// - IMenuItem SelectedItem { get; set; } + IMenuItem? SelectedItem { get; set; } /// /// Gets the submenu items. diff --git a/src/Avalonia.Controls/IMenuItem.cs b/src/Avalonia.Controls/IMenuItem.cs index 132d565cb7..94d761f725 100644 --- a/src/Avalonia.Controls/IMenuItem.cs +++ b/src/Avalonia.Controls/IMenuItem.cs @@ -1,4 +1,6 @@ -namespace Avalonia.Controls +#nullable enable + +namespace Avalonia.Controls { /// /// Represents a . @@ -29,7 +31,7 @@ /// /// Gets the parent . /// - new IMenuElement Parent { get; } + new IMenuElement? Parent { get; } /// /// Raises a click event on the menu item. diff --git a/src/Avalonia.Controls/Menu.cs b/src/Avalonia.Controls/Menu.cs index 7205af0e75..3733137714 100644 --- a/src/Avalonia.Controls/Menu.cs +++ b/src/Avalonia.Controls/Menu.cs @@ -4,6 +4,8 @@ using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.Layout; +#nullable enable + namespace Avalonia.Controls { /// diff --git a/src/Avalonia.Controls/MenuBase.cs b/src/Avalonia.Controls/MenuBase.cs index 4554cb2bcf..0434928280 100644 --- a/src/Avalonia.Controls/MenuBase.cs +++ b/src/Avalonia.Controls/MenuBase.cs @@ -8,6 +8,8 @@ using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.LogicalTree; +#nullable enable + namespace Avalonia.Controls { /// @@ -51,9 +53,7 @@ namespace Avalonia.Controls /// The menu interaction handler. public MenuBase(IMenuInteractionHandler interactionHandler) { - Contract.Requires(interactionHandler != null); - - InteractionHandler = interactionHandler; + InteractionHandler = interactionHandler ?? throw new ArgumentNullException(nameof(interactionHandler)); } /// @@ -77,7 +77,7 @@ namespace Avalonia.Controls IMenuInteractionHandler IMenu.InteractionHandler => InteractionHandler; /// - IMenuItem IMenuElement.SelectedItem + IMenuItem? IMenuElement.SelectedItem { get { diff --git a/src/Avalonia.Controls/MenuItem.cs b/src/Avalonia.Controls/MenuItem.cs index 912abc6de3..aab099911b 100644 --- a/src/Avalonia.Controls/MenuItem.cs +++ b/src/Avalonia.Controls/MenuItem.cs @@ -12,6 +12,8 @@ using Avalonia.Interactivity; using Avalonia.LogicalTree; using Avalonia.VisualTree; +#nullable enable + namespace Avalonia.Controls { /// @@ -22,7 +24,7 @@ namespace Avalonia.Controls /// /// Defines the property. /// - public static readonly DirectProperty CommandProperty = + public static readonly DirectProperty CommandProperty = Button.CommandProperty.AddOwner( menuItem => menuItem.Command, (menuItem, command) => menuItem.Command = command, @@ -94,10 +96,10 @@ namespace Avalonia.Controls private static readonly ITemplate DefaultPanel = new FuncTemplate(() => new StackPanel()); - private ICommand _command; + private ICommand? _command; private bool _commandCanExecute = true; - private Popup _popup; - private IDisposable _gridHack; + private Popup? _popup; + private IDisposable? _gridHack; /// /// Initializes static members of the class. @@ -166,7 +168,7 @@ namespace Avalonia.Controls /// /// Gets or sets the command associated with the menu item. /// - public ICommand Command + public ICommand? Command { get { return _command; } set { SetAndRaise(CommandProperty, ref _command, value); } @@ -246,7 +248,7 @@ namespace Avalonia.Controls bool IMenuItem.IsPointerOverSubMenu => _popup?.IsPointerOverPopup ?? false; /// - IMenuElement IMenuItem.Parent => Parent as IMenuElement; + IMenuElement? IMenuItem.Parent => Parent as IMenuElement; protected override bool IsEnabledCore => base.IsEnabledCore && _commandCanExecute; @@ -254,7 +256,7 @@ namespace Avalonia.Controls bool IMenuElement.MoveSelection(NavigationDirection direction, bool wrap) => MoveSelection(direction, wrap); /// - IMenuItem IMenuElement.SelectedItem + IMenuItem? IMenuElement.SelectedItem { get { @@ -551,7 +553,7 @@ namespace Avalonia.Controls /// The property change event. private void IsSelectedChanged(AvaloniaPropertyChangedEventArgs e) { - if ((bool)e.NewValue) + if ((bool)e.NewValue!) { Focus(); } @@ -563,7 +565,7 @@ namespace Avalonia.Controls /// The property change event. private void SubMenuOpenChanged(AvaloniaPropertyChangedEventArgs e) { - var value = (bool)e.NewValue; + var value = (bool)e.NewValue!; if (value) { diff --git a/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs b/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs index 2a7ea12d79..be92b89b73 100644 --- a/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs +++ b/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs @@ -3,7 +3,6 @@ using Avalonia.Input; using Avalonia.Input.Raw; using Avalonia.Interactivity; using Avalonia.LogicalTree; -using Avalonia.Platform; using Avalonia.Rendering; using Avalonia.Threading; using Avalonia.VisualTree; @@ -235,7 +234,9 @@ namespace Avalonia.Controls.Platform // If the the parent is an IMenu which successfully moved its selection, // and the current menu is open then close the current menu and open the // new menu. - if (item.IsSubMenuOpen && item.Parent is IMenu) + if (item.IsSubMenuOpen && + item.Parent is IMenu && + item.Parent.SelectedItem is object) { item.Close(); Open(item.Parent.SelectedItem, true); @@ -385,7 +386,7 @@ namespace Avalonia.Controls.Platform { if (e.Source == Menu) { - Menu.MoveSelection(NavigationDirection.First, true); + Menu?.MoveSelection(NavigationDirection.First, true); } } From 226c57b7d792b9ab1de96afd1ebec71d4a9a086f Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 10 Jul 2020 13:25:30 +0200 Subject: [PATCH 007/344] Ensure that Open is called on main menu. --- .../Platform/DefaultMenuInteractionHandler.cs | 5 +++++ .../DefaultMenuInteractionHandlerTests.cs | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs b/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs index be92b89b73..6d6398bcda 100644 --- a/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs +++ b/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs @@ -364,6 +364,11 @@ namespace Avalonia.Controls.Platform } else { + if (item.IsTopLevel && item.Parent is IMainMenu mainMenu) + { + mainMenu.Open(); + } + Open(item, false); } diff --git a/tests/Avalonia.Controls.UnitTests/Platform/DefaultMenuInteractionHandlerTests.cs b/tests/Avalonia.Controls.UnitTests/Platform/DefaultMenuInteractionHandlerTests.cs index 97b6bf9d24..64f35049ce 100644 --- a/tests/Avalonia.Controls.UnitTests/Platform/DefaultMenuInteractionHandlerTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Platform/DefaultMenuInteractionHandlerTests.cs @@ -124,6 +124,24 @@ namespace Avalonia.Controls.UnitTests.Platform Assert.True(e.Handled); } + [Fact] + public void Click_On_TopLevel_Calls_MainMenu_Open() + { + var target = new DefaultMenuInteractionHandler(false); + var menu = new Mock(); + menu.As(); + + var item = Mock.Of(x => + x.IsTopLevel == true && + x.HasSubMenu == true && + x.Parent == menu.Object); + + var e = CreatePressed(item); + + target.PointerPressed(item, e); + menu.Verify(x => x.Open()); + } + [Fact] public void Click_On_Open_TopLevel_Menu_Closes_Menu() { From f0eafa70d0d7e8b066cf01cccfe5c6c85774ec20 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 10 Jul 2020 20:27:42 +0200 Subject: [PATCH 008/344] Added LightDismissOverlayLayer.InputPassThroughElement. Which implements something similar to UWP's `FlyoutBase.OverlayInputPassThroughElement`. With this feature, `Menu`/`MenuItem` can use `IsLightDismissEnabled="True"` fixing #3965 for top-level menus. --- src/Avalonia.Controls/Menu.cs | 17 ++++++++++++++ .../Primitives/LightDismissOverlayLayer.cs | 22 ++++++++++++++++++- src/Avalonia.Themes.Default/MenuItem.xaml | 2 ++ src/Avalonia.Themes.Fluent/MenuItem.xaml | 5 +++-- .../Rendering/ICustomSimpleHitTest.cs | 11 ++++++++++ .../Rendering/SceneGraph/Scene.cs | 6 +++++ 6 files changed, 60 insertions(+), 3 deletions(-) diff --git a/src/Avalonia.Controls/Menu.cs b/src/Avalonia.Controls/Menu.cs index 3733137714..f74daa791d 100644 --- a/src/Avalonia.Controls/Menu.cs +++ b/src/Avalonia.Controls/Menu.cs @@ -1,4 +1,5 @@ using Avalonia.Controls.Platform; +using Avalonia.Controls.Primitives; using Avalonia.Controls.Templates; using Avalonia.Input; using Avalonia.Interactivity; @@ -16,6 +17,8 @@ namespace Avalonia.Controls private static readonly ITemplate DefaultPanel = new FuncTemplate(() => new StackPanel { Orientation = Orientation.Horizontal }); + private LightDismissOverlayLayer? _overlay; + /// /// Initializes a new instance of the class. /// @@ -45,6 +48,13 @@ namespace Avalonia.Controls return; } + if (_overlay?.InputPassThroughElement == this) + { + _overlay.InputPassThroughElement = null; + } + + _overlay = null; + foreach (var i in ((IMenu)this).SubItems) { i.Close(); @@ -68,6 +78,13 @@ namespace Avalonia.Controls return; } + _overlay = LightDismissOverlayLayer.GetLightDismissOverlayLayer(this); + + if (_overlay is object) + { + _overlay.InputPassThroughElement = this; + } + IsOpen = true; RaiseEvent(new RoutedEventArgs diff --git a/src/Avalonia.Controls/Primitives/LightDismissOverlayLayer.cs b/src/Avalonia.Controls/Primitives/LightDismissOverlayLayer.cs index ede9a9b635..752eedb68a 100644 --- a/src/Avalonia.Controls/Primitives/LightDismissOverlayLayer.cs +++ b/src/Avalonia.Controls/Primitives/LightDismissOverlayLayer.cs @@ -1,6 +1,8 @@ using System; using System.Linq; using Avalonia.Controls.Templates; +using Avalonia.Input; +using Avalonia.Rendering; using Avalonia.Styling; using Avalonia.VisualTree; @@ -11,8 +13,10 @@ namespace Avalonia.Controls.Primitives /// /// A layer that is used to dismiss a when the user clicks outside. /// - public class LightDismissOverlayLayer : Border + public class LightDismissOverlayLayer : Border, ICustomHitTest { + public IInputElement? InputPassThroughElement { get; set; } + /// /// Returns the light dismiss overlay for a specified visual. /// @@ -37,5 +41,21 @@ namespace Avalonia.Controls.Primitives return manager?.LightDismissOverlayLayer; } + + public bool HitTest(Point point) + { + if (InputPassThroughElement is object) + { + var p = point.Transform(this.TransformToVisual(VisualRoot)!.Value); + var hit = VisualRoot.GetVisualAt(p, x => x != this); + + if (hit is object) + { + return !InputPassThroughElement.IsVisualAncestorOf(hit); + } + } + + return true; + } } } diff --git a/src/Avalonia.Themes.Default/MenuItem.xaml b/src/Avalonia.Themes.Default/MenuItem.xaml index 0eb87166b2..b1f536a704 100644 --- a/src/Avalonia.Themes.Default/MenuItem.xaml +++ b/src/Avalonia.Themes.Default/MenuItem.xaml @@ -59,6 +59,7 @@ Grid.Column="4"/> + IsLightDismissEnabled="True" + IsOpen="{TemplateBinding IsSubMenuOpen, Mode=TwoWay}"> + /// Allows customization of hit-testing for all renderers. + /// + /// + /// Note that this interface can only used to make a portion of a control non-hittable, it + /// cannot expand the hittable area of a control. + /// + public interface ICustomHitTest : ICustomSimpleHitTest + { + } + public static class CustomSimpleHitTestExtensions { public static bool HitTestCustom(this IVisual visual, Point point) diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs index 0f6001516d..4f5c97cdff 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs @@ -304,6 +304,12 @@ namespace Avalonia.Rendering.SceneGraph clipped = !node.GeometryClip.FillContains(controlPoint.Value); } + if (!clipped && node.Visual is ICustomHitTest custom) + { + var controlPoint = _sceneRoot.Visual.TranslatePoint(_point, node.Visual); + clipped = !custom.HitTest(controlPoint.Value); + } + return !clipped; } From a8b7e879387a1d83cd724877195c27ac3e320be3 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sun, 12 Jul 2020 15:22:00 +0200 Subject: [PATCH 009/344] Added IRecyclingDataTemplate. In #4218 we imported `IElementFactory` from WinUI which is broadly analogous to a recycling datatemplate for lists. In Avalonia this implement `IDataTemplate` in order to have a common base class for all types of data templates. The problem with this is that `IDataTemplate` already had a `SupportsRecycling` property which is incompatible with the way recycling is implemented in `IElementFactory`. Instead, introduce an `IRecyclingDataTemplate` to signal data templates that support recycling. --- .../Generators/TreeItemContainerGenerator.cs | 1 - .../Presenters/ContentPresenter.cs | 21 +++++++------- .../Repeater/ElementFactory.cs | 2 -- .../Repeater/ItemTemplateWrapper.cs | 1 - .../Templates/FuncDataTemplate.cs | 29 ++++++++++++++----- .../Templates/FuncTemplate`2.cs | 6 ++-- .../Templates/IDataTemplate.cs | 12 ++++---- .../Templates/IRecyclingDataTemplate.cs | 25 ++++++++++++++++ .../Diagnostics/ViewLocator.cs | 2 -- .../Templates/DataTemplate.cs | 11 ++++--- .../Templates/TreeDataTemplate.cs | 2 -- .../TreeViewTests.cs | 2 -- 12 files changed, 71 insertions(+), 43 deletions(-) create mode 100644 src/Avalonia.Controls/Templates/IRecyclingDataTemplate.cs diff --git a/src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs b/src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs index cd1ce3deae..9e65ef5f81 100644 --- a/src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs +++ b/src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs @@ -142,7 +142,6 @@ namespace Avalonia.Controls.Generators private readonly IDataTemplate _inner; public WrapperTreeDataTemplate(IDataTemplate inner) => _inner = inner; public IControl Build(object param) => _inner.Build(param); - public bool SupportsRecycling => _inner.SupportsRecycling; public bool Match(object data) => _inner.Match(data); public InstancedBinding ItemsSelector(object item) => null; } diff --git a/src/Avalonia.Controls/Presenters/ContentPresenter.cs b/src/Avalonia.Controls/Presenters/ContentPresenter.cs index c4571505ba..8837901816 100644 --- a/src/Avalonia.Controls/Presenters/ContentPresenter.cs +++ b/src/Avalonia.Controls/Presenters/ContentPresenter.cs @@ -86,7 +86,7 @@ namespace Avalonia.Controls.Presenters private IControl _child; private bool _createdChild; - private IDataTemplate _dataTemplate; + private IRecyclingDataTemplate _recyclingDataTemplate; private readonly BorderRenderHelper _borderRenderer = new BorderRenderHelper(); /// @@ -281,7 +281,7 @@ namespace Avalonia.Controls.Presenters protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e) { base.OnAttachedToLogicalTree(e); - _dataTemplate = null; + _recyclingDataTemplate = null; _createdChild = false; InvalidateMeasure(); } @@ -307,22 +307,21 @@ namespace Avalonia.Controls.Presenters { var dataTemplate = this.FindDataTemplate(content, ContentTemplate) ?? FuncDataTemplate.Default; - // We have content and it isn't a control, so if the new data template is the same - // as the old data template, try to recycle the existing child control to display - // the new data. - if (dataTemplate == _dataTemplate && dataTemplate.SupportsRecycling) + if (dataTemplate is IRecyclingDataTemplate rdt) { - newChild = oldChild; + var toRecycle = rdt == _recyclingDataTemplate ? oldChild : null; + newChild = rdt.Build(content, toRecycle); + _recyclingDataTemplate = rdt; } else { - _dataTemplate = dataTemplate; - newChild = _dataTemplate.Build(content); + newChild = dataTemplate.Build(content); + _recyclingDataTemplate = null; } } else { - _dataTemplate = null; + _recyclingDataTemplate = null; } return newChild; @@ -422,7 +421,7 @@ namespace Avalonia.Controls.Presenters LogicalChildren.Remove(Child); ((ISetInheritanceParent)Child).SetParent(Child.Parent); Child = null; - _dataTemplate = null; + _recyclingDataTemplate = null; } InvalidateMeasure(); diff --git a/src/Avalonia.Controls/Repeater/ElementFactory.cs b/src/Avalonia.Controls/Repeater/ElementFactory.cs index 1c1b71af88..644e077221 100644 --- a/src/Avalonia.Controls/Repeater/ElementFactory.cs +++ b/src/Avalonia.Controls/Repeater/ElementFactory.cs @@ -4,8 +4,6 @@ namespace Avalonia.Controls { public abstract class ElementFactory : IElementFactory { - bool IDataTemplate.SupportsRecycling => false; - public IControl Build(object data) { return GetElementCore(new ElementFactoryGetArgs { Data = data }); diff --git a/src/Avalonia.Controls/Repeater/ItemTemplateWrapper.cs b/src/Avalonia.Controls/Repeater/ItemTemplateWrapper.cs index 4b784375a9..dd97cde218 100644 --- a/src/Avalonia.Controls/Repeater/ItemTemplateWrapper.cs +++ b/src/Avalonia.Controls/Repeater/ItemTemplateWrapper.cs @@ -13,7 +13,6 @@ namespace Avalonia.Controls public ItemTemplateWrapper(IDataTemplate dataTemplate) => _dataTemplate = dataTemplate; - public bool SupportsRecycling => false; public IControl Build(object param) => GetElement(null, param); public bool Match(object data) => _dataTemplate.Match(data); diff --git a/src/Avalonia.Controls/Templates/FuncDataTemplate.cs b/src/Avalonia.Controls/Templates/FuncDataTemplate.cs index d454a29021..1afd86a11e 100644 --- a/src/Avalonia.Controls/Templates/FuncDataTemplate.cs +++ b/src/Avalonia.Controls/Templates/FuncDataTemplate.cs @@ -6,7 +6,7 @@ namespace Avalonia.Controls.Templates /// /// Builds a control for a piece of data. /// - public class FuncDataTemplate : FuncTemplate, IDataTemplate + public class FuncDataTemplate : FuncTemplate, IRecyclingDataTemplate { /// /// The default data template used in the case where no matching data template is found. @@ -30,10 +30,8 @@ namespace Avalonia.Controls.Templates }, true); - /// - /// The implementation of the method. - /// private readonly Func _match; + private readonly bool _supportsRecycling; /// /// Initializes a new instance of the class. @@ -70,12 +68,9 @@ namespace Avalonia.Controls.Templates Contract.Requires(match != null); _match = match; - SupportsRecycling = supportsRecycling; + _supportsRecycling = supportsRecycling; } - /// - public bool SupportsRecycling { get; } - /// /// Checks to see if this data template matches the specified data. /// @@ -88,6 +83,24 @@ namespace Avalonia.Controls.Templates return _match(data); } + /// + /// Creates or recycles a control to display the specified data. + /// + /// The data to display. + /// An optional control to recycle. + /// + /// The control if supplied and applicable to + /// , otherwise a new control. + /// + /// + /// The caller should ensure that any control passed to + /// originated from the same data template. + /// + public IControl Build(object data, IControl existing) + { + return _supportsRecycling && existing is object ? existing : Build(data); + } + /// /// Determines of an object is of the specified type. /// diff --git a/src/Avalonia.Controls/Templates/FuncTemplate`2.cs b/src/Avalonia.Controls/Templates/FuncTemplate`2.cs index d08616b968..cd0e3ad603 100644 --- a/src/Avalonia.Controls/Templates/FuncTemplate`2.cs +++ b/src/Avalonia.Controls/Templates/FuncTemplate`2.cs @@ -1,5 +1,7 @@ using System; +#nullable enable + namespace Avalonia.Controls.Templates { /// @@ -18,9 +20,7 @@ namespace Avalonia.Controls.Templates /// The function used to create the control. public FuncTemplate(Func func) { - Contract.Requires(func != null); - - _func = func; + _func = func ?? throw new ArgumentNullException(nameof(func)); } /// diff --git a/src/Avalonia.Controls/Templates/IDataTemplate.cs b/src/Avalonia.Controls/Templates/IDataTemplate.cs index cfde029eb8..0368748a0b 100644 --- a/src/Avalonia.Controls/Templates/IDataTemplate.cs +++ b/src/Avalonia.Controls/Templates/IDataTemplate.cs @@ -1,3 +1,7 @@ +using System; + +#nullable enable + namespace Avalonia.Controls.Templates { /// @@ -5,12 +9,6 @@ namespace Avalonia.Controls.Templates /// public interface IDataTemplate : ITemplate { - /// - /// Gets a value indicating whether the data template supports recycling of the generated - /// control. - /// - bool SupportsRecycling { get; } - /// /// Checks to see if this data template matches the specified data. /// @@ -20,4 +18,4 @@ namespace Avalonia.Controls.Templates /// bool Match(object data); } -} \ No newline at end of file +} diff --git a/src/Avalonia.Controls/Templates/IRecyclingDataTemplate.cs b/src/Avalonia.Controls/Templates/IRecyclingDataTemplate.cs new file mode 100644 index 0000000000..25956a9c9a --- /dev/null +++ b/src/Avalonia.Controls/Templates/IRecyclingDataTemplate.cs @@ -0,0 +1,25 @@ +#nullable enable + +namespace Avalonia.Controls.Templates +{ + /// + /// An that supports recycling existing elements. + /// + public interface IRecyclingDataTemplate : IDataTemplate + { + /// + /// Creates or recycles a control to display the specified data. + /// + /// The data to display. + /// An optional control to recycle. + /// + /// The control if supplied and applicable to + /// , otherwise a new control. + /// + /// + /// The caller should ensure that any control passed to + /// originated from the same data template. + /// + IControl Build(object data, IControl? existing); + } +} diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewLocator.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewLocator.cs index c06fbec801..be3564e781 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewLocator.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewLocator.cs @@ -7,8 +7,6 @@ namespace Avalonia.Diagnostics { internal class ViewLocator : IDataTemplate { - public bool SupportsRecycling => false; - public IControl Build(object data) { var name = data.GetType().FullName.Replace("ViewModel", "View"); diff --git a/src/Markup/Avalonia.Markup.Xaml/Templates/DataTemplate.cs b/src/Markup/Avalonia.Markup.Xaml/Templates/DataTemplate.cs index 5663d08412..07c5451135 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Templates/DataTemplate.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Templates/DataTemplate.cs @@ -5,7 +5,7 @@ using Avalonia.Metadata; namespace Avalonia.Markup.Xaml.Templates { - public class DataTemplate : IDataTemplate + public class DataTemplate : IRecyclingDataTemplate { public Type DataType { get; set; } @@ -14,8 +14,6 @@ namespace Avalonia.Markup.Xaml.Templates [TemplateContent] public object Content { get; set; } - public bool SupportsRecycling { get; set; } = true; - public bool Match(object data) { if (DataType == null) @@ -28,6 +26,11 @@ namespace Avalonia.Markup.Xaml.Templates } } - public IControl Build(object data) => TemplateContent.Load(Content).Control; + public IControl Build(object data) => Build(data, null); + + public IControl Build(object data, IControl existing) + { + return existing ?? TemplateContent.Load(Content).Control; + } } } diff --git a/src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs b/src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs index b96486235a..b8e1c2df80 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs @@ -18,8 +18,6 @@ namespace Avalonia.Markup.Xaml.Templates [AssignBinding] public Binding ItemsSource { get; set; } - public bool SupportsRecycling { get; set; } = true; - public bool Match(object data) { if (DataType == null) diff --git a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs index c1bd45bcad..c25ad19027 100644 --- a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs @@ -1273,8 +1273,6 @@ namespace Avalonia.Controls.UnitTests return new TextBlock { Text = node.Value }; } - public bool SupportsRecycling => false; - public InstancedBinding ItemsSelector(object item) { var obs = ExpressionObserver.Create(item, o => (o as Node).Children); From e87697f901798c7f1fffe7bcca3a36c59f8c2a3c Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Wed, 15 Jul 2020 06:19:14 +0200 Subject: [PATCH 010/344] Allow combining TextTrimming and TextWrapping --- .../GenericTextParagraphProperties.cs | 15 +- .../TextFormatting/ShapedTextCharacters.cs | 3 +- .../TextCollapsingProperties.cs | 23 ++ .../TextFormatting/TextCollapsingStyle.cs | 18 ++ .../Media/TextFormatting/TextFormatterImpl.cs | 221 +++++------------- .../Media/TextFormatting/TextLayout.cs | 62 +++-- .../Media/TextFormatting/TextLine.cs | 11 + .../Media/TextFormatting/TextLineImpl.cs | 136 ++++++++++- .../Media/TextFormatting/TextLineMetrics.cs | 11 +- .../TextFormatting/TextParagraphProperties.cs | 5 - .../TextTrailingCharacterEllipsis.cs | 33 +++ .../TextTrailingWordEllipsis.cs | 37 +++ .../Unicode/LineBreakEnumerator.cs | 1 - src/Avalonia.Visuals/Media/TextWrapping.cs | 16 +- .../Media/TextFormatting/TextLayoutTests.cs | 12 +- .../Media/TextFormatting/TextLineTests.cs | 58 +++++ 16 files changed, 441 insertions(+), 221 deletions(-) create mode 100644 src/Avalonia.Visuals/Media/TextFormatting/TextCollapsingProperties.cs create mode 100644 src/Avalonia.Visuals/Media/TextFormatting/TextCollapsingStyle.cs create mode 100644 src/Avalonia.Visuals/Media/TextFormatting/TextTrailingCharacterEllipsis.cs create mode 100644 src/Avalonia.Visuals/Media/TextFormatting/TextTrailingWordEllipsis.cs diff --git a/src/Avalonia.Visuals/Media/TextFormatting/GenericTextParagraphProperties.cs b/src/Avalonia.Visuals/Media/TextFormatting/GenericTextParagraphProperties.cs index c4302aecec..8e7d934bca 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/GenericTextParagraphProperties.cs +++ b/src/Avalonia.Visuals/Media/TextFormatting/GenericTextParagraphProperties.cs @@ -4,14 +4,12 @@ { private TextAlignment _textAlignment; private TextWrapping _textWrapping; - private TextTrimming _textTrimming; private double _lineHeight; public GenericTextParagraphProperties( TextRunProperties defaultTextRunProperties, TextAlignment textAlignment = TextAlignment.Left, - TextWrapping textWrapping = TextWrapping.WrapWithOverflow, - TextTrimming textTrimming = TextTrimming.None, + TextWrapping textWrapping = TextWrapping.NoWrap, double lineHeight = 0) { DefaultTextRunProperties = defaultTextRunProperties; @@ -20,8 +18,6 @@ _textWrapping = textWrapping; - _textTrimming = textTrimming; - _lineHeight = lineHeight; } @@ -31,8 +27,6 @@ public override TextWrapping TextWrapping => _textWrapping; - public override TextTrimming TextTrimming => _textTrimming; - public override double LineHeight => _lineHeight; /// @@ -50,13 +44,6 @@ { _textWrapping = textWrapping; } - /// - /// Set text trimming - /// - internal void SetTextTrimming(TextTrimming textTrimming) - { - _textTrimming = textTrimming; - } /// /// Set line height diff --git a/src/Avalonia.Visuals/Media/TextFormatting/ShapedTextCharacters.cs b/src/Avalonia.Visuals/Media/TextFormatting/ShapedTextCharacters.cs index b71fe5bc3c..9e67a03f45 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/ShapedTextCharacters.cs +++ b/src/Avalonia.Visuals/Media/TextFormatting/ShapedTextCharacters.cs @@ -1,5 +1,4 @@ -using Avalonia.Media.TextFormatting.Unicode; -using Avalonia.Utilities; +using Avalonia.Utilities; namespace Avalonia.Media.TextFormatting { diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextCollapsingProperties.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextCollapsingProperties.cs new file mode 100644 index 0000000000..ffd65423a3 --- /dev/null +++ b/src/Avalonia.Visuals/Media/TextFormatting/TextCollapsingProperties.cs @@ -0,0 +1,23 @@ +namespace Avalonia.Media.TextFormatting +{ + /// + /// Properties of text collapsing + /// + public abstract class TextCollapsingProperties + { + /// + /// Gets the width in which the collapsible range is constrained to + /// + public abstract double Width { get; } + + /// + /// Gets the text run that is used as collapsing symbol + /// + public abstract TextRun Symbol { get; } + + /// + /// Gets the style of collapsing + /// + public abstract TextCollapsingStyle Style { get; } + } +} diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextCollapsingStyle.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextCollapsingStyle.cs new file mode 100644 index 0000000000..1523cc4d9a --- /dev/null +++ b/src/Avalonia.Visuals/Media/TextFormatting/TextCollapsingStyle.cs @@ -0,0 +1,18 @@ +namespace Avalonia.Media.TextFormatting +{ + /// + /// Text collapsing style + /// + public enum TextCollapsingStyle + { + /// + /// Collapse trailing characters + /// + TrailingCharacter, + + /// + /// Collapse trailing words + /// + TrailingWord, + } +} diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs index 3ad23f3504..061949a5c9 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs +++ b/src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs @@ -1,49 +1,41 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using Avalonia.Media.TextFormatting.Unicode; -using Avalonia.Platform; -using Avalonia.Utilities; namespace Avalonia.Media.TextFormatting { internal class TextFormatterImpl : TextFormatter { - private static readonly ReadOnlySlice s_ellipsis = new ReadOnlySlice(new[] { '\u2026' }); - /// public override TextLine FormatLine(ITextSource textSource, int firstTextSourceIndex, double paragraphWidth, TextParagraphProperties paragraphProperties, TextLineBreak previousLineBreak = null) { - var textTrimming = paragraphProperties.TextTrimming; var textWrapping = paragraphProperties.TextWrapping; - TextLine textLine = null; var textRuns = FetchTextRuns(textSource, firstTextSourceIndex, previousLineBreak, out var nextLineBreak); var textRange = GetTextRange(textRuns); - if (textTrimming != TextTrimming.None) - { - textLine = PerformTextTrimming(textRuns, textRange, paragraphWidth, paragraphProperties); - } - else + TextLine textLine; + + switch (textWrapping) { - switch (textWrapping) - { - case TextWrapping.NoWrap: - { - var textLineMetrics = - TextLineMetrics.Create(textRuns, textRange, paragraphWidth, paragraphProperties); + case TextWrapping.NoWrap: + { + var textLineMetrics = + TextLineMetrics.Create(textRuns, textRange, paragraphWidth, paragraphProperties); - textLine = new TextLineImpl(textRuns, textLineMetrics, nextLineBreak); - break; - } - case TextWrapping.WrapWithOverflow: - case TextWrapping.Wrap: - { - textLine = PerformTextWrapping(textRuns, textRange, paragraphWidth, paragraphProperties); - break; - } - } + textLine = new TextLineImpl(textRuns, textLineMetrics, nextLineBreak); + break; + } + case TextWrapping.WrapWithOverflow: + case TextWrapping.Wrap: + { + textLine = PerformTextWrapping(textRuns, textRange, paragraphWidth, paragraphProperties); + break; + } + default: + throw new ArgumentOutOfRangeException(); } return textLine; @@ -174,87 +166,6 @@ namespace Avalonia.Media.TextFormatting return false; } - /// - /// Performs text trimming and returns a trimmed line. - /// - /// The text runs to perform the trimming on. - /// The text range that is covered by the text runs. - /// A value that specifies the width of the paragraph that the line fills. - /// A value that represents paragraph properties, - /// such as TextWrapping, TextAlignment, or TextStyle. - /// - private static TextLine PerformTextTrimming(IReadOnlyList textRuns, TextRange textRange, - double paragraphWidth, TextParagraphProperties paragraphProperties) - { - var textTrimming = paragraphProperties.TextTrimming; - var availableWidth = paragraphWidth; - var currentWidth = 0.0; - var runIndex = 0; - - while (runIndex < textRuns.Count) - { - var currentRun = textRuns[runIndex]; - - currentWidth += currentRun.GlyphRun.Bounds.Width; - - if (currentWidth > availableWidth) - { - var ellipsisRun = CreateEllipsisRun(currentRun.Properties); - - var measuredLength = MeasureText(currentRun, availableWidth - ellipsisRun.GlyphRun.Bounds.Width); - - if (textTrimming == TextTrimming.WordEllipsis) - { - if (measuredLength < textRange.End) - { - var currentBreakPosition = 0; - - var lineBreaker = new LineBreakEnumerator(currentRun.Text); - - while (currentBreakPosition < measuredLength && lineBreaker.MoveNext()) - { - var nextBreakPosition = lineBreaker.Current.PositionWrap; - - if (nextBreakPosition == 0) - { - break; - } - - if (nextBreakPosition > measuredLength) - { - break; - } - - currentBreakPosition = nextBreakPosition; - } - - measuredLength = currentBreakPosition; - } - } - - var splitResult = SplitTextRuns(textRuns, measuredLength); - - var trimmedRuns = new List(splitResult.First.Count + 1); - - trimmedRuns.AddRange(splitResult.First); - - trimmedRuns.Add(ellipsisRun); - - var textLineMetrics = - TextLineMetrics.Create(trimmedRuns, textRange, paragraphWidth, paragraphProperties); - - return new TextLineImpl(trimmedRuns, textLineMetrics); - } - - availableWidth -= currentRun.GlyphRun.Bounds.Width; - - runIndex++; - } - - return new TextLineImpl(textRuns, - TextLineMetrics.Create(textRuns, textRange, paragraphWidth, paragraphProperties)); - } - /// /// Performs text wrapping returns a list of text lines. /// @@ -269,7 +180,7 @@ namespace Avalonia.Media.TextFormatting var availableWidth = paragraphWidth; var currentWidth = 0.0; var runIndex = 0; - var length = 0; + var currentLength = 0; while (runIndex < textRuns.Count) { @@ -279,58 +190,53 @@ namespace Avalonia.Media.TextFormatting { var measuredLength = MeasureText(currentRun, paragraphWidth - currentWidth); + var breakFound = false; + + var currentBreakPosition = 0; + if (measuredLength < currentRun.Text.Length) { - if (paragraphProperties.TextWrapping == TextWrapping.WrapWithOverflow) - { - var lineBreaker = new LineBreakEnumerator(currentRun.Text.Skip(measuredLength)); + var lineBreaker = new LineBreakEnumerator(currentRun.Text); - if (lineBreaker.MoveNext()) - { - measuredLength += lineBreaker.Current.PositionWrap; - } - else - { - measuredLength = currentRun.Text.Length; - } - } - else + while (currentBreakPosition < measuredLength && lineBreaker.MoveNext()) { - var currentBreakPosition = -1; + var nextBreakPosition = lineBreaker.Current.PositionWrap; - var lineBreaker = new LineBreakEnumerator(currentRun.Text); - - while (currentBreakPosition < measuredLength && lineBreaker.MoveNext()) + if (nextBreakPosition == 0 || nextBreakPosition > measuredLength) { - var nextBreakPosition = lineBreaker.Current.PositionWrap; + break; + } - if (nextBreakPosition == 0) - { - break; - } + breakFound = lineBreaker.Current.Required || + lineBreaker.Current.PositionWrap != currentRun.Text.Length; - if (nextBreakPosition > measuredLength) - { - break; - } + currentBreakPosition = nextBreakPosition; + } + } - currentBreakPosition = nextBreakPosition; - } + if (breakFound) + { + measuredLength = currentBreakPosition; + } + else + { + if (paragraphProperties.TextWrapping == TextWrapping.WrapWithOverflow) + { + var lineBreaker = new LineBreakEnumerator(currentRun.Text.Skip(currentBreakPosition)); - if (currentBreakPosition != -1) + if (lineBreaker.MoveNext()) { - measuredLength = currentBreakPosition; + measuredLength = currentBreakPosition + lineBreaker.Current.PositionWrap; } - } } - length += measuredLength; + currentLength += measuredLength; - var splitResult = SplitTextRuns(textRuns, length); + var splitResult = SplitTextRuns(textRuns, currentLength); var textLineMetrics = TextLineMetrics.Create(splitResult.First, - new TextRange(textRange.Start, length), paragraphWidth, paragraphProperties); + new TextRange(textRange.Start, currentLength), paragraphWidth, paragraphProperties); var lineBreak = splitResult.Second != null && splitResult.Second.Count > 0 ? new TextLineBreak(splitResult.Second) : @@ -341,7 +247,7 @@ namespace Avalonia.Media.TextFormatting currentWidth += currentRun.GlyphRun.Bounds.Width; - length += currentRun.GlyphRun.Characters.Length; + currentLength += currentRun.GlyphRun.Characters.Length; runIndex++; } @@ -356,7 +262,7 @@ namespace Avalonia.Media.TextFormatting /// The text run. /// The available width. /// - private static int MeasureText(ShapedTextCharacters textCharacters, double availableWidth) + internal static int MeasureText(ShapedTextCharacters textCharacters, double availableWidth) { var glyphRun = textCharacters.GlyphRun; @@ -391,10 +297,8 @@ namespace Avalonia.Media.TextFormatting } else { - for (var i = 0; i < glyphRun.GlyphAdvances.Length; i++) + foreach (var advance in glyphRun.GlyphAdvances) { - var advance = glyphRun.GlyphAdvances[i]; - if (currentWidth + advance > availableWidth) { break; @@ -423,21 +327,6 @@ namespace Avalonia.Media.TextFormatting return lastCluster - firstCluster; } - /// - /// Creates an ellipsis. - /// - /// The text run properties. - /// - private static ShapedTextCharacters CreateEllipsisRun(TextRunProperties properties) - { - var formatterImpl = AvaloniaLocator.Current.GetService(); - - var glyphRun = formatterImpl.ShapeText(s_ellipsis, properties.Typeface, properties.FontRenderingEmSize, - properties.CultureInfo); - - return new ShapedTextCharacters(glyphRun, properties); - } - /// /// Gets the text range that is covered by the text runs. /// @@ -470,7 +359,7 @@ namespace Avalonia.Media.TextFormatting /// The text run's. /// The length to split at. /// The split text runs. - private static SplitTextRunsResult SplitTextRuns(IReadOnlyList textRuns, int length) + internal static SplitTextRunsResult SplitTextRuns(IReadOnlyList textRuns, int length) { var currentLength = 0; @@ -543,7 +432,7 @@ namespace Avalonia.Media.TextFormatting return new SplitTextRunsResult(textRuns, null); } - private readonly struct SplitTextRunsResult + internal readonly struct SplitTextRunsResult { public SplitTextRunsResult(IReadOnlyList first, IReadOnlyList second) { diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs index 54745144c8..92db6b69c4 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs +++ b/src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs @@ -1,9 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; -using Avalonia.Media.TextFormatting.Unicode; using Avalonia.Utilities; -using Avalonia.Platform; namespace Avalonia.Media.TextFormatting { @@ -17,6 +15,7 @@ namespace Avalonia.Media.TextFormatting private readonly ReadOnlySlice _text; private readonly TextParagraphProperties _paragraphProperties; private readonly IReadOnlyList> _textStyleOverrides; + private readonly TextTrimming _textTrimming; /// /// Initializes a new instance of the class. @@ -54,9 +53,11 @@ namespace Avalonia.Media.TextFormatting new ReadOnlySlice(text.AsMemory()); _paragraphProperties = - CreateTextParagraphProperties(typeface, fontSize, foreground, textAlignment, textWrapping, textTrimming, + CreateTextParagraphProperties(typeface, fontSize, foreground, textAlignment, textWrapping, textDecorations, lineHeight); + _textTrimming = textTrimming; + _textStyleOverrides = textStyleOverrides; LineHeight = lineHeight; @@ -143,18 +144,16 @@ namespace Avalonia.Media.TextFormatting /// The foreground. /// The text alignment. /// The text wrapping. - /// The text trimming. /// The text decorations. /// The height of each line of text. /// private static TextParagraphProperties CreateTextParagraphProperties(Typeface typeface, double fontSize, - IBrush foreground, TextAlignment textAlignment, TextWrapping textWrapping, TextTrimming textTrimming, + IBrush foreground, TextAlignment textAlignment, TextWrapping textWrapping, TextDecorationCollection textDecorations, double lineHeight) { var textRunStyle = new GenericTextRunProperties(typeface, fontSize, textDecorations, foreground); - return new GenericTextParagraphProperties(textRunStyle, textAlignment, textWrapping, textTrimming, - lineHeight); + return new GenericTextParagraphProperties(textRunStyle, textAlignment, textWrapping, lineHeight); } /// @@ -214,25 +213,44 @@ namespace Avalonia.Media.TextFormatting var textSource = new FormattedTextSource(_text, _paragraphProperties.DefaultTextRunProperties, _textStyleOverrides); - TextLineBreak previousLineBreak = null; + TextLine previousLine = null; - while (currentPosition < _text.Length && (MaxLines == 0 || textLines.Count < MaxLines)) + while (currentPosition < _text.Length) { var textLine = TextFormatter.Current.FormatLine(textSource, currentPosition, MaxWidth, - _paragraphProperties, previousLineBreak); + _paragraphProperties, previousLine?.LineBreak); - previousLineBreak = textLine.LineBreak; + currentPosition += textLine.TextRange.Length; - textLines.Add(textLine); + if (textLines.Count > 0) + { + if (textLines.Count == MaxLines || !double.IsPositiveInfinity(MaxHeight) && + height + textLine.LineMetrics.Size.Height > MaxHeight) + { + if (previousLine?.LineBreak != null && _textTrimming != TextTrimming.None) + { + var collapsedLine = + previousLine.Collapse(GetCollapsingProperties(MaxWidth)); - UpdateBounds(textLine, ref width, ref height); + textLines[textLines.Count - 1] = collapsedLine; + } + + break; + } + } - if (!double.IsPositiveInfinity(MaxHeight) && height > MaxHeight) + var hasOverflowed = textLine.LineMetrics.HasOverflowed; + + if (hasOverflowed && _textTrimming != TextTrimming.None) { - break; + textLine = textLine.Collapse(GetCollapsingProperties(MaxWidth)); } - currentPosition += textLine.TextRange.Length; + textLines.Add(textLine); + + UpdateBounds(textLine, ref width, ref height); + + previousLine = textLine; if (currentPosition != _text.Length || textLine.LineBreak == null) { @@ -250,6 +268,18 @@ namespace Avalonia.Media.TextFormatting } } + private TextCollapsingProperties GetCollapsingProperties(double width) + { + return _textTrimming switch + { + TextTrimming.CharacterEllipsis => new TextTrailingCharacterEllipsis(width, + _paragraphProperties.DefaultTextRunProperties), + TextTrimming.WordEllipsis => new TextTrailingWordEllipsis(width, + _paragraphProperties.DefaultTextRunProperties), + _ => throw new ArgumentOutOfRangeException(), + }; + } + private readonly struct FormattedTextSource : ITextSource { private readonly ReadOnlySlice _text; diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextLine.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextLine.cs index c3b7dfc77a..3e3258f38a 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/TextLine.cs +++ b/src/Avalonia.Visuals/Media/TextFormatting/TextLine.cs @@ -39,6 +39,11 @@ namespace Avalonia.Media.TextFormatting /// public abstract TextLineBreak LineBreak { get; } + /// + /// Client to get a boolean value indicates whether a line has been collapsed + /// + public abstract bool HasCollapsed { get; } + /// /// Draws the at the given origin. /// @@ -46,6 +51,12 @@ namespace Avalonia.Media.TextFormatting /// The origin. public abstract void Draw(DrawingContext drawingContext, Point origin); + /// + /// Client to collapse the line and get a collapsed line that fits for display + /// + /// a list of collapsing properties + public abstract TextLine Collapse(params TextCollapsingProperties[] collapsingPropertiesList); + /// /// Client to get the character hit corresponding to the specified /// distance from the beginning of the line. diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs index a1a9b50793..820c943aea 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs +++ b/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs @@ -1,4 +1,6 @@ using System.Collections.Generic; +using Avalonia.Media.TextFormatting.Unicode; +using Avalonia.Platform; namespace Avalonia.Media.TextFormatting { @@ -7,11 +9,12 @@ namespace Avalonia.Media.TextFormatting private readonly IReadOnlyList _textRuns; public TextLineImpl(IReadOnlyList textRuns, TextLineMetrics lineMetrics, - TextLineBreak lineBreak = null) + TextLineBreak lineBreak = null, bool hasCollapsed = false) { _textRuns = textRuns; LineMetrics = lineMetrics; LineBreak = lineBreak; + HasCollapsed = hasCollapsed; } /// @@ -26,6 +29,9 @@ namespace Avalonia.Media.TextFormatting /// public override TextLineBreak LineBreak { get; } + /// + public override bool HasCollapsed { get; } + /// public override void Draw(DrawingContext drawingContext, Point origin) { @@ -41,6 +47,98 @@ namespace Avalonia.Media.TextFormatting } } + public override TextLine Collapse(params TextCollapsingProperties[] collapsingPropertiesList) + { + if (collapsingPropertiesList == null || collapsingPropertiesList.Length == 0) + { + return this; + } + + var collapsingProperties = collapsingPropertiesList[0]; + var runIndex = 0; + var currentWidth = 0.0; + var textRange = TextRange; + var collapsedLength = 0; + TextLineMetrics textLineMetrics; + + var shapedSymbol = CreateShapedSymbol(collapsingProperties.Symbol); + + var availableWidth = collapsingProperties.Width - shapedSymbol.Bounds.Width; + + while (runIndex < _textRuns.Count) + { + var currentRun = _textRuns[runIndex]; + + currentWidth += currentRun.GlyphRun.Bounds.Width; + + if (currentWidth > availableWidth) + { + var measuredLength = TextFormatterImpl.MeasureText(currentRun, availableWidth); + + var currentBreakPosition = 0; + + if (measuredLength < textRange.End) + { + var lineBreaker = new LineBreakEnumerator(currentRun.Text); + + while (currentBreakPosition < measuredLength && lineBreaker.MoveNext()) + { + var nextBreakPosition = lineBreaker.Current.PositionWrap; + + if (nextBreakPosition == 0) + { + break; + } + + if (nextBreakPosition > measuredLength) + { + break; + } + + currentBreakPosition = nextBreakPosition; + } + } + + if (collapsingProperties.Style == TextCollapsingStyle.TrailingWord) + { + measuredLength = currentBreakPosition; + } + + collapsedLength += measuredLength; + + var splitResult = TextFormatterImpl.SplitTextRuns(_textRuns, collapsedLength); + + var shapedTextCharacters = new List(splitResult.First.Count + 1); + + shapedTextCharacters.AddRange(splitResult.First); + + shapedTextCharacters.Add(shapedSymbol); + + textRange = new TextRange(textRange.Start, collapsedLength); + + var shapedWidth = GetShapedWidth(shapedTextCharacters); + + textLineMetrics = new TextLineMetrics(new Size(shapedWidth, LineMetrics.Size.Height), + LineMetrics.TextBaseline, textRange, false); + + return new TextLineImpl(shapedTextCharacters, textLineMetrics, LineBreak, true); + } + + availableWidth -= currentRun.GlyphRun.Bounds.Width; + + collapsedLength += currentRun.GlyphRun.Characters.Length; + + runIndex++; + } + + textLineMetrics = + new TextLineMetrics(LineMetrics.Size.WithWidth(LineMetrics.Size.Width + shapedSymbol.Bounds.Width), + LineMetrics.TextBaseline, TextRange, LineMetrics.HasOverflowed); + + return new TextLineImpl(new List(_textRuns) { shapedSymbol }, textLineMetrics, null, + true); + } + /// public override CharacterHit GetCharacterHitFromDistance(double distance) { @@ -230,5 +328,41 @@ namespace Avalonia.Media.TextFormatting return runIndex; } + + /// + /// Creates a shaped symbol. + /// + /// The symbol run to shape. + /// + /// The shaped symbol. + /// + internal static ShapedTextCharacters CreateShapedSymbol(TextRun textRun) + { + var formatterImpl = AvaloniaLocator.Current.GetService(); + + var glyphRun = formatterImpl.ShapeText(textRun.Text, textRun.Properties.Typeface, textRun.Properties.FontRenderingEmSize, + textRun.Properties.CultureInfo); + + return new ShapedTextCharacters(glyphRun, textRun.Properties); + } + + /// + /// Gets the shaped width of specified shaped text characters. + /// + /// The shaped text characters. + /// + /// The shaped width. + /// + private static double GetShapedWidth(IReadOnlyList shapedTextCharacters) + { + var shapedWidth = 0.0; + + for (var i = 0; i < shapedTextCharacters.Count; i++) + { + shapedWidth += shapedTextCharacters[i].Bounds.Width; + } + + return shapedWidth; + } } } diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextLineMetrics.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextLineMetrics.cs index 2f7809ff35..6875cc1c04 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/TextLineMetrics.cs +++ b/src/Avalonia.Visuals/Media/TextFormatting/TextLineMetrics.cs @@ -9,11 +9,12 @@ namespace Avalonia.Media.TextFormatting /// public readonly struct TextLineMetrics { - public TextLineMetrics(Size size, double textBaseline, TextRange textRange) + public TextLineMetrics(Size size, double textBaseline, TextRange textRange, bool hasOverflowed) { Size = size; TextBaseline = textBaseline; TextRange = textRange; + HasOverflowed = hasOverflowed; } /// @@ -37,6 +38,12 @@ namespace Avalonia.Media.TextFormatting /// public double TextBaseline { get; } + /// + /// Gets a boolean value that indicates whether content of the line overflows + /// the specified paragraph width. + /// + public bool HasOverflowed { get; } + /// /// Creates the text line metrics. /// @@ -83,7 +90,7 @@ namespace Avalonia.Media.TextFormatting descent - ascent + lineGap : paragraphProperties.LineHeight); - return new TextLineMetrics(size, -ascent, textRange); + return new TextLineMetrics(size, -ascent, textRange, size.Width > paragraphWidth); } } } diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextParagraphProperties.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextParagraphProperties.cs index 39eb695404..3ecd1aafd9 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/TextParagraphProperties.cs +++ b/src/Avalonia.Visuals/Media/TextFormatting/TextParagraphProperties.cs @@ -26,11 +26,6 @@ /// public abstract TextWrapping TextWrapping { get; } - /// - /// Gets the text trimming. - /// - public abstract TextTrimming TextTrimming { get; } - /// /// Paragraph's line height /// diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextTrailingCharacterEllipsis.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextTrailingCharacterEllipsis.cs new file mode 100644 index 0000000000..4bd46e8c75 --- /dev/null +++ b/src/Avalonia.Visuals/Media/TextFormatting/TextTrailingCharacterEllipsis.cs @@ -0,0 +1,33 @@ +using Avalonia.Utilities; + +namespace Avalonia.Media.TextFormatting +{ + /// + /// a collapsing properties to collapse whole line toward the end + /// at character granularity and with ellipsis being the collapsing symbol + /// + public class TextTrailingCharacterEllipsis : TextCollapsingProperties + { + private static readonly ReadOnlySlice s_ellipsis = new ReadOnlySlice(new[] { '\u2026' }); + + /// + /// Construct a text trailing character ellipsis collapsing properties + /// + /// width in which collapsing is constrained to + /// text run properties of ellispis symbol + public TextTrailingCharacterEllipsis(double width, TextRunProperties textRunProperties) + { + Width = width; + Symbol = new TextCharacters(s_ellipsis, textRunProperties); + } + + /// + public sealed override double Width { get; } + + /// + public sealed override TextRun Symbol { get; } + + /// + public sealed override TextCollapsingStyle Style { get; } = TextCollapsingStyle.TrailingCharacter; + } +} diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextTrailingWordEllipsis.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextTrailingWordEllipsis.cs new file mode 100644 index 0000000000..9dffddd207 --- /dev/null +++ b/src/Avalonia.Visuals/Media/TextFormatting/TextTrailingWordEllipsis.cs @@ -0,0 +1,37 @@ +using Avalonia.Utilities; + +namespace Avalonia.Media.TextFormatting +{ + /// + /// a collapsing properties to collapse whole line toward the end + /// at word granularity and with ellipsis being the collapsing symbol + /// + public class TextTrailingWordEllipsis : TextCollapsingProperties + { + private static readonly ReadOnlySlice s_ellipsis = new ReadOnlySlice(new[] { '\u2026' }); + + /// + /// Construct a text trailing word ellipsis collapsing properties + /// + /// width in which collapsing is constrained to + /// text run properties of ellispis symbol + public TextTrailingWordEllipsis( + double width, + TextRunProperties textRunProperties + ) + { + Width = width; + Symbol = new TextCharacters(s_ellipsis, textRunProperties); + } + + + /// + public sealed override double Width { get; } + + /// + public sealed override TextRun Symbol { get; } + + /// + public sealed override TextCollapsingStyle Style { get; } = TextCollapsingStyle.TrailingWord; + } +} diff --git a/src/Avalonia.Visuals/Media/TextFormatting/Unicode/LineBreakEnumerator.cs b/src/Avalonia.Visuals/Media/TextFormatting/Unicode/LineBreakEnumerator.cs index 26f7721128..76bb9ac44f 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/Unicode/LineBreakEnumerator.cs +++ b/src/Avalonia.Visuals/Media/TextFormatting/Unicode/LineBreakEnumerator.cs @@ -109,7 +109,6 @@ namespace Avalonia.Media.TextFormatting.Unicode { case PairBreakType.DI: // Direct break shouldBreak = true; - _lastPos = _pos; break; case PairBreakType.IN: // possible indirect break diff --git a/src/Avalonia.Visuals/Media/TextWrapping.cs b/src/Avalonia.Visuals/Media/TextWrapping.cs index d649bda23f..b7915e5612 100644 --- a/src/Avalonia.Visuals/Media/TextWrapping.cs +++ b/src/Avalonia.Visuals/Media/TextWrapping.cs @@ -5,13 +5,6 @@ namespace Avalonia.Media /// public enum TextWrapping { - /// - /// Line-breaking occurs if the line overflows the available block width. - /// However, a line may overflow the block width if the line breaking algorithm - /// cannot determine a break opportunity, as in the case of a very long word. - /// - WrapWithOverflow, - /// /// Text should not wrap. /// @@ -20,6 +13,13 @@ namespace Avalonia.Media /// /// Text can wrap. /// - Wrap + Wrap, + + /// + /// Line-breaking occurs if the line overflows the available block width. + /// However, a line may overflow the block width if the line breaking algorithm + /// cannot determine a break opportunity, as in the case of a very long word. + /// + WrapWithOverflow } } diff --git a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs index 43a791b2cb..bf41381b52 100644 --- a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs +++ b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs @@ -490,10 +490,10 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting } } - [InlineData("0123456789\r0123456789", 2)] - [InlineData("0123456789", 1)] + [InlineData("0123456789\r0123456789")] + [InlineData("0123456789")] [Theory] - public void Should_Include_Last_Line_When_Constraint_Is_Surpassed(string text, int numberOfLines) + public void Should_Include_First_Line_When_Constraint_Is_Surpassed(string text) { using (Start()) { @@ -508,11 +508,11 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting Typeface.Default, 12, Brushes.Black.ToImmutable(), - maxHeight: lineHeight * numberOfLines - lineHeight * 0.5); + maxHeight: lineHeight - lineHeight * 0.5); - Assert.Equal(numberOfLines, layout.TextLines.Count); + Assert.Equal(1, layout.TextLines.Count); - Assert.Equal(numberOfLines * lineHeight, layout.Size.Height); + Assert.Equal(lineHeight, layout.Size.Height); } } diff --git a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs index ed00d6aaed..f0951c61d3 100644 --- a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs +++ b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs @@ -162,6 +162,64 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting } } + [InlineData("01234 01234", 8, TextCollapsingStyle.TrailingCharacter, "01234 0\u2026")] + [InlineData("01234 01234", 8, TextCollapsingStyle.TrailingWord, "01234 \u2026")] + [Theory] + public void Should_Collapse_Line(string text, int numberOfCharacters, TextCollapsingStyle style, string expected) + { + using (Start()) + { + var defaultProperties = new GenericTextRunProperties(Typeface.Default); + + var textSource = new SingleBufferTextSource(text, defaultProperties); + + var formatter = new TextFormatterImpl(); + + var textLine = + formatter.FormatLine(textSource, 0, double.PositiveInfinity, + new GenericTextParagraphProperties(defaultProperties)); + + Assert.False(textLine.HasCollapsed); + + var glyphTypeface = Typeface.Default.GlyphTypeface; + + var scale = defaultProperties.FontRenderingEmSize / glyphTypeface.DesignEmHeight; + + var width = 1.0; + + for (var i = 0; i < numberOfCharacters; i++) + { + var glyph = glyphTypeface.GetGlyph(text[i]); + + width += glyphTypeface.GetGlyphAdvance(glyph) * scale; + } + + TextCollapsingProperties collapsingProperties; + + if (style == TextCollapsingStyle.TrailingCharacter) + { + collapsingProperties = new TextTrailingCharacterEllipsis(width, defaultProperties); + } + else + { + collapsingProperties = new TextTrailingWordEllipsis(width, defaultProperties); + } + + var collapsedLine = textLine.Collapse(collapsingProperties); + + Assert.True(collapsedLine.HasCollapsed); + + var trimmedText = collapsedLine.TextRuns.SelectMany(x => x.Text).ToArray(); + + Assert.Equal(expected.Length, trimmedText.Length); + + for (var i = 0; i < expected.Length; i++) + { + Assert.Equal(expected[i], trimmedText[i]); + } + } + } + private static IDisposable Start() { var disposable = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface From 62fd036d55e010fe6b59a35ae0178aab5247162f Mon Sep 17 00:00:00 2001 From: FoggyFinder Date: Wed, 15 Jul 2020 13:17:06 +0300 Subject: [PATCH 011/344] small adjustment to avoid IndexOutOfRangeException --- .../DateTimePickers/DatePicker.cs | 16 ++++++++++------ .../DateTimePickers/DatePickerPresenter.cs | 16 ++++++++-------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/Avalonia.Controls/DateTimePickers/DatePicker.cs b/src/Avalonia.Controls/DateTimePickers/DatePicker.cs index 5d3311e8c6..a41c159980 100644 --- a/src/Avalonia.Controls/DateTimePickers/DatePicker.cs +++ b/src/Avalonia.Controls/DateTimePickers/DatePicker.cs @@ -88,7 +88,7 @@ namespace Avalonia.Controls AvaloniaProperty.RegisterDirect(nameof(SelectedDate), x => x.SelectedDate, (x, v) => x.SelectedDate = v); - //Template Items + // Template Items private Button _flyoutButton; private TextBlock _dayText; private TextBlock _monthText; @@ -359,10 +359,14 @@ namespace Avalonia.Controls } } - Grid.SetColumn(_spacer1, 1); - Grid.SetColumn(_spacer2, 3); - _spacer1.IsVisible = columnIndex > 1; - _spacer2.IsVisible = columnIndex > 2; + var isSpacer1Visible = columnIndex > 1; + var isSpacer2Visible = columnIndex > 2; + // ternary conditional operator is used to make sure grid cells will be validated + Grid.SetColumn(_spacer1, isSpacer1Visible ? 1 : 0); + Grid.SetColumn(_spacer2, isSpacer2Visible ? 3 : 0); + + _spacer1.IsVisible = isSpacer1Visible; + _spacer2.IsVisible = isSpacer2Visible; } private void SetSelectedDateText() @@ -398,7 +402,7 @@ namespace Avalonia.Controls var deltaY = _presenter.GetOffsetForPopup(); - //The extra 5 px I think is related to default popup placement behavior + // The extra 5 px I think is related to default popup placement behavior _popup.Host.ConfigurePosition(_popup.PlacementTarget, PlacementMode.AnchorAndGravity, new Point(0, deltaY + 5), Primitives.PopupPositioning.PopupAnchor.Bottom, Primitives.PopupPositioning.PopupGravity.Bottom, Primitives.PopupPositioning.PopupPositionerConstraintAdjustment.SlideY); diff --git a/src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs b/src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs index 8b86e46e88..0da46bb74a 100644 --- a/src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs +++ b/src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs @@ -77,7 +77,7 @@ namespace Avalonia.Controls DatePicker.YearVisibleProperty.AddOwner(x => x.YearVisible, (x, v) => x.YearVisible = v); - //Template Items + // Template Items private Grid _pickerContainer; private Button _acceptButton; private Button _dismissButton; @@ -107,7 +107,7 @@ namespace Avalonia.Controls private bool _yearVisible = true; private DateTimeOffset _syncDate; - private GregorianCalendar _calendar; + private readonly GregorianCalendar _calendar; private bool _suppressUpdateSelection; public DatePickerPresenter() @@ -234,7 +234,7 @@ namespace Avalonia.Controls protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { base.OnApplyTemplate(e); - //These are requirements, so throw if not found + // These are requirements, so throw if not found _pickerContainer = e.NameScope.Get("PickerContainer"); _monthHost = e.NameScope.Get("MonthHost"); _dayHost = e.NameScope.Get("DayHost"); @@ -326,7 +326,7 @@ namespace Avalonia.Controls /// private void InitPicker() { - //OnApplyTemplate must've been called before we can init here... + // OnApplyTemplate must've been called before we can init here... if (_pickerContainer == null) return; @@ -344,7 +344,7 @@ namespace Avalonia.Controls SetGrid(); - //Date should've been set when we reach this point + // Date should've been set when we reach this point var dt = Date; if (DayVisible) { @@ -433,12 +433,12 @@ namespace Avalonia.Controls } } - private void OnDismissButtonClicked(object sender, Avalonia.Interactivity.RoutedEventArgs e) + private void OnDismissButtonClicked(object sender, RoutedEventArgs e) { OnDismiss(); } - private void OnAcceptButtonClicked(object sender, Avalonia.Interactivity.RoutedEventArgs e) + private void OnAcceptButtonClicked(object sender, RoutedEventArgs e) { Date = _syncDate; OnConfirmed(); @@ -471,7 +471,7 @@ namespace Avalonia.Controls _syncDate = newDate; - //We don't need to update the days if not displaying day, not february + // We don't need to update the days if not displaying day, not february if (!DayVisible || _syncDate.Month != 2) return; From b43c8f4ceffeb1a86bcc6ecb13250715f6ff4f62 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 15 Jul 2020 17:59:30 +0200 Subject: [PATCH 012/344] Added `Popup.OverlayInputPassThroughElement`. --- src/Avalonia.Controls/Primitives/Popup.cs | 28 +++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs index c97d90baed..71efd322ec 100644 --- a/src/Avalonia.Controls/Primitives/Popup.cs +++ b/src/Avalonia.Controls/Primitives/Popup.cs @@ -87,6 +87,12 @@ namespace Avalonia.Controls.Primitives public static readonly StyledProperty OverlayDismissEventPassThroughProperty = AvaloniaProperty.Register(nameof(OverlayDismissEventPassThrough)); + public static readonly DirectProperty OverlayInputPassThroughElementProperty = + AvaloniaProperty.RegisterDirect( + nameof(OverlayInputPassThroughElement), + o => o.OverlayInputPassThroughElement, + (o, v) => o.OverlayInputPassThroughElement = v); + /// /// Defines the property. /// @@ -125,6 +131,7 @@ namespace Avalonia.Controls.Primitives private bool _isOpen; private bool _ignoreIsOpenChanged; private PopupOpenState? _openState; + private IInputElement _overlayInputPassThroughElement; /// /// Initializes static members of the class. @@ -286,6 +293,16 @@ namespace Avalonia.Controls.Primitives set => SetValue(OverlayDismissEventPassThroughProperty, value); } + /// + /// Gets or sets an element that should receive pointer input events even when underneath + /// the popup's overlay. + /// + public IInputElement OverlayInputPassThroughElement + { + get => _overlayInputPassThroughElement; + set => SetAndRaise(OverlayInputPassThroughElementProperty, ref _overlayInputPassThroughElement, value); + } + /// /// Gets or sets the Horizontal offset of the popup in relation to the . /// @@ -430,7 +447,14 @@ namespace Avalonia.Controls.Primitives if (dismissLayer != null) { dismissLayer.IsVisible = true; - DeferCleanup(Disposable.Create(() => dismissLayer.IsVisible = false)); + dismissLayer.InputPassThroughElement = _overlayInputPassThroughElement; + + DeferCleanup(Disposable.Create(() => + { + dismissLayer.IsVisible = false; + dismissLayer.InputPassThroughElement = null; + })); + DeferCleanup(SubscribeToEventHandler>( dismissLayer, PointerPressedDismissOverlay, @@ -694,7 +718,7 @@ namespace Avalonia.Controls.Primitives private void WindowLostFocus() { - if(IsLightDismissEnabled) + if (IsLightDismissEnabled) Close(); } From 8916fda98db209ed511f3395547b9179c5764ce6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Onak?= Date: Wed, 15 Jul 2020 21:24:23 +0200 Subject: [PATCH 013/344] Force recalculation of column width after edit is completed --- src/Avalonia.Controls.DataGrid/DataGrid.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Avalonia.Controls.DataGrid/DataGrid.cs b/src/Avalonia.Controls.DataGrid/DataGrid.cs index fe9656a00b..7e921944ea 100644 --- a/src/Avalonia.Controls.DataGrid/DataGrid.cs +++ b/src/Avalonia.Controls.DataGrid/DataGrid.cs @@ -3922,6 +3922,12 @@ namespace Avalonia.Controls dataGridCell: editingCell); EditingRow.InvalidateDesiredHeight(); + var column = editingCell.OwningColumn; + if (column.Width.IsSizeToCells || column.Width.IsAuto) + {// Invalidate desired width and force recalculation + column.SetWidthDesiredValue(0); + EditingRow.OwningGrid.AutoSizeColumn(column, editingCell.DesiredSize.Width); + } } // We're done, so raise the CellEditEnded event From 5bce867f5258fba927267c84a1c252053199d6e1 Mon Sep 17 00:00:00 2001 From: FoggyFinder Date: Thu, 16 Jul 2020 09:47:30 +0300 Subject: [PATCH 014/344] additional check for presenter --- .../DateTimePickers/DatePickerPresenter.cs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs b/src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs index 0da46bb74a..31527ccb16 100644 --- a/src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs +++ b/src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs @@ -348,8 +348,7 @@ namespace Avalonia.Controls var dt = Date; if (DayVisible) { - GregorianCalendar gc = new GregorianCalendar(); - var maxDays = gc.GetDaysInMonth(dt.Year, dt.Month); + var maxDays = _calendar.GetDaysInMonth(dt.Year, dt.Month); _daySelector.MaximumValue = maxDays; _daySelector.MinimumValue = 1; _daySelector.SelectedValue = dt.Day; @@ -407,10 +406,14 @@ namespace Avalonia.Controls } } - Grid.SetColumn(_spacer1, 1); - Grid.SetColumn(_spacer2, 3); - _spacer1.IsVisible = columnIndex > 1; - _spacer2.IsVisible = columnIndex > 2; + var isSpacer1Visible = columnIndex > 1; + var isSpacer2Visible = columnIndex > 2; + // ternary conditional operator is used to make sure grid cells will be validated + Grid.SetColumn(_spacer1, isSpacer1Visible ? 1 : 0); + Grid.SetColumn(_spacer2, isSpacer2Visible ? 3 : 0); + + _spacer1.IsVisible = isSpacer1Visible; + _spacer2.IsVisible = isSpacer2Visible; } private void SetInitialFocus() From bebe9ee3739364ed11ae4819acef07a9bb3890ac Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 13 Jul 2020 17:25:15 +0200 Subject: [PATCH 015/344] Bind ListBox.SelectedItems again. Was removed accidentally. --- samples/ControlCatalog/Pages/ListBoxPage.xaml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/samples/ControlCatalog/Pages/ListBoxPage.xaml b/samples/ControlCatalog/Pages/ListBoxPage.xaml index 47b4ce7151..f4d81418ac 100644 --- a/samples/ControlCatalog/Pages/ListBoxPage.xaml +++ b/samples/ControlCatalog/Pages/ListBoxPage.xaml @@ -10,7 +10,13 @@ HorizontalAlignment="Center" Spacing="16"> - + From 0301d80c302cde4a60aeec2b6816e91cc66fa8d0 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Tue, 14 Jul 2020 22:04:47 +0200 Subject: [PATCH 016/344] Added failing test for removing selected item with BeginInit. --- .../Primitives/SelectingItemsControlTests.cs | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs index fe9c7b1261..9ef2750ff3 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs @@ -531,6 +531,7 @@ namespace Avalonia.Controls.UnitTests.Primitives }; target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); target.SelectedIndex = 1; Assert.Equal(items[1], target.SelectedItem); @@ -549,6 +550,45 @@ namespace Avalonia.Controls.UnitTests.Primitives Assert.NotNull(receivedArgs); Assert.Empty(receivedArgs.AddedItems); Assert.Equal(new[] { removed }, receivedArgs.RemovedItems); + Assert.False(items.Single().IsSelected); + } + + [Fact] + public void Removing_Selected_Item_Should_Clear_Selection_With_BeginInit() + { + var items = new AvaloniaList + { + new Item(), + new Item(), + }; + + var target = new SelectingItemsControl(); + target.BeginInit(); + target.Items = items; + target.Template = Template(); + target.EndInit(); + + target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); + target.SelectedIndex = 0; + + Assert.Equal(items[0], target.SelectedItem); + Assert.Equal(0, target.SelectedIndex); + + SelectionChangedEventArgs receivedArgs = null; + + target.SelectionChanged += (_, args) => receivedArgs = args; + + var removed = items[0]; + + items.RemoveAt(0); + + Assert.Null(target.SelectedItem); + Assert.Equal(-1, target.SelectedIndex); + Assert.NotNull(receivedArgs); + Assert.Empty(receivedArgs.AddedItems); + Assert.Equal(new[] { removed }, receivedArgs.RemovedItems); + Assert.False(items.Single().IsSelected); } [Fact] From c37144b59633f8f52f917a77f5bceb7c0e678647 Mon Sep 17 00:00:00 2001 From: Andrey Kunchev Date: Thu, 16 Jul 2020 13:03:26 +0300 Subject: [PATCH 017/344] add failing unit tests for #4306 --- .../ListBoxTests_Multiple.cs | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 tests/Avalonia.Controls.UnitTests/ListBoxTests_Multiple.cs diff --git a/tests/Avalonia.Controls.UnitTests/ListBoxTests_Multiple.cs b/tests/Avalonia.Controls.UnitTests/ListBoxTests_Multiple.cs new file mode 100644 index 0000000000..7c7cdd08db --- /dev/null +++ b/tests/Avalonia.Controls.UnitTests/ListBoxTests_Multiple.cs @@ -0,0 +1,126 @@ +using System.Linq; +using Avalonia.Controls.Presenters; +using Avalonia.Controls.Templates; +using Avalonia.Input; +using Avalonia.Styling; +using Avalonia.UnitTests; +using Avalonia.VisualTree; +using Xunit; + +namespace Avalonia.Controls.UnitTests +{ + public class ListBoxTests_Multiple + { + [Fact] + public void Focusing_Item_With_Shift_And_Arrow_Key_Should_Add_To_Selection() + { + var target = new ListBox + { + Template = new FuncControlTemplate(CreateListBoxTemplate), + Items = new[] { "Foo", "Bar", "Baz " }, + SelectionMode = SelectionMode.Multiple + }; + + ApplyTemplate(target); + + target.SelectedItem = "Foo"; + + target.Presenter.Panel.Children[1].RaiseEvent(new GotFocusEventArgs + { + RoutedEvent = InputElement.GotFocusEvent, + NavigationMethod = NavigationMethod.Directional, + KeyModifiers = KeyModifiers.Shift + }); + + Assert.Equal(new[] { "Foo", "Bar" }, target.SelectedItems); + } + + [Fact] + public void Focusing_Item_With_Ctrl_And_Arrow_Key_Should_Add_To_Selection() + { + var target = new ListBox + { + Template = new FuncControlTemplate(CreateListBoxTemplate), + Items = new[] { "Foo", "Bar", "Baz " }, + SelectionMode = SelectionMode.Multiple + }; + + ApplyTemplate(target); + + target.SelectedItem = "Foo"; + + target.Presenter.Panel.Children[1].RaiseEvent(new GotFocusEventArgs + { + RoutedEvent = InputElement.GotFocusEvent, + NavigationMethod = NavigationMethod.Directional, + KeyModifiers = KeyModifiers.Control + }); + + Assert.Equal(new[] { "Foo", "Bar" }, target.SelectedItems); + } + + [Fact] + public void Focusing_Selected_Item_With_Ctrl_And_Arrow_Key_Should_Remove_From_Selection() + { + var target = new ListBox + { + Template = new FuncControlTemplate(CreateListBoxTemplate), + Items = new[] { "Foo", "Bar", "Baz " }, + SelectionMode = SelectionMode.Multiple + }; + + ApplyTemplate(target); + + target.SelectedItems.Add("Foo"); + target.SelectedItems.Add("Bar"); + + target.Presenter.Panel.Children[0].RaiseEvent(new GotFocusEventArgs + { + RoutedEvent = InputElement.GotFocusEvent, + NavigationMethod = NavigationMethod.Directional, + KeyModifiers = KeyModifiers.Control + }); + + Assert.Equal(new[] { "Bar" }, target.SelectedItems); + } + + private Control CreateListBoxTemplate(ITemplatedControl parent, INameScope scope) + { + return new ScrollViewer + { + Template = new FuncControlTemplate(CreateScrollViewerTemplate), + Content = new ItemsPresenter + { + Name = "PART_ItemsPresenter", + [~ItemsPresenter.ItemsProperty] = parent.GetObservable(ItemsControl.ItemsProperty).ToBinding(), + }.RegisterInNameScope(scope) + }; + } + + private Control CreateScrollViewerTemplate(ITemplatedControl parent, INameScope scope) + { + return new ScrollContentPresenter + { + Name = "PART_ContentPresenter", + [~ContentPresenter.ContentProperty] = + parent.GetObservable(ContentControl.ContentProperty).ToBinding(), + }.RegisterInNameScope(scope); + } + + private void ApplyTemplate(ListBox target) + { + // Apply the template to the ListBox itself. + target.ApplyTemplate(); + + // Then to its inner ScrollViewer. + var scrollViewer = (ScrollViewer)target.GetVisualChildren().Single(); + scrollViewer.ApplyTemplate(); + + // Then make the ScrollViewer create its child. + ((ContentPresenter)scrollViewer.Presenter).UpdateChild(); + + // Now the ItemsPresenter should be reigstered, so apply its template. + target.Presenter.ApplyTemplate(); + } + } +} From c08d88afcff791837d28b0a1dd73105da0d1cc6e Mon Sep 17 00:00:00 2001 From: Andrey Kunchev Date: Thu, 16 Jul 2020 12:47:26 +0300 Subject: [PATCH 018/344] pass key modifiers to focus --- src/Avalonia.Controls/ItemsControl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/ItemsControl.cs b/src/Avalonia.Controls/ItemsControl.cs index 6e0ad66699..1aa7945901 100644 --- a/src/Avalonia.Controls/ItemsControl.cs +++ b/src/Avalonia.Controls/ItemsControl.cs @@ -295,7 +295,7 @@ namespace Avalonia.Controls if (next != null) { - focus.Focus(next, NavigationMethod.Directional); + focus.Focus(next, NavigationMethod.Directional, e.KeyModifiers); e.Handled = true; } From e5c373acd06489b0e715282158488712259723eb Mon Sep 17 00:00:00 2001 From: Andrey Kunchev Date: Thu, 16 Jul 2020 12:48:12 +0300 Subject: [PATCH 019/344] pass ctrl key state to selection logic in listbox --- src/Avalonia.Controls/ListBox.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/ListBox.cs b/src/Avalonia.Controls/ListBox.cs index 3c21cd2c38..a085bfb6bc 100644 --- a/src/Avalonia.Controls/ListBox.cs +++ b/src/Avalonia.Controls/ListBox.cs @@ -136,7 +136,8 @@ namespace Avalonia.Controls e.Handled = UpdateSelectionFromEventSource( e.Source, true, - (e.KeyModifiers & KeyModifiers.Shift) != 0); + (e.KeyModifiers & KeyModifiers.Shift) != 0, + (e.KeyModifiers & KeyModifiers.Control) != 0); } } From 125ae96859df3bf6e602bc9f85171234fdd16f55 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 16 Jul 2020 12:29:33 +0200 Subject: [PATCH 020/344] Handle selected items being removed. Fixes #4293. --- .../Primitives/SelectingItemsControl.cs | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs index c915dc70b6..59b7777b1b 100644 --- a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs +++ b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs @@ -692,14 +692,24 @@ namespace Avalonia.Controls.Primitives } } - foreach (var i in e.SelectedIndices) + if (e.SelectedIndices.Count > 0 || e.DeselectedIndices.Count > 0) { - Mark(i.GetAt(0), true); - } + foreach (var i in e.SelectedIndices) + { + Mark(i.GetAt(0), true); + } - foreach (var i in e.DeselectedIndices) + foreach (var i in e.DeselectedIndices) + { + Mark(i.GetAt(0), false); + } + } + else if (e.DeselectedItems.Count > 0) { - Mark(i.GetAt(0), false); + // (De)selected indices being empty means that a selected item was removed from + // the Items (it can't tell us the index of the item because the index is no longer + // valid). In this case, we just update the selection state of all containers. + UpdateContainerSelection(); } var newSelectedIndex = SelectedIndex; From e042266678779029d8660335bdb475e3b2207278 Mon Sep 17 00:00:00 2001 From: FoggyFinder Date: Thu, 16 Jul 2020 14:07:55 +0300 Subject: [PATCH 021/344] add some properties to `AffectsRender` list --- src/Avalonia.Controls/TickBar.cs | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/Avalonia.Controls/TickBar.cs b/src/Avalonia.Controls/TickBar.cs index 22145d8742..6ea5277a55 100644 --- a/src/Avalonia.Controls/TickBar.cs +++ b/src/Avalonia.Controls/TickBar.cs @@ -39,11 +39,15 @@ namespace Avalonia.Controls { static TickBar() { - AffectsRender(ReservedSpaceProperty, + AffectsRender(FillProperty, + IsDirectionReversedProperty, + ReservedSpaceProperty, MaximumProperty, MinimumProperty, OrientationProperty, - TickFrequencyProperty); + PlacementProperty, + TickFrequencyProperty, + TicksProperty); } public TickBar() : base() @@ -137,7 +141,7 @@ namespace Avalonia.Controls /// /// The Ticks property contains collection of value of type Double which /// are the logical positions use to draw the ticks. - /// The property value is a . + /// The property value is a . /// public AvaloniaList Ticks { @@ -169,7 +173,6 @@ namespace Avalonia.Controls public static readonly StyledProperty PlacementProperty = AvaloniaProperty.Register(nameof(Placement), 0d); - /// /// Placement property specified how the Tick will be placed. /// This property affects the way ticks are drawn. @@ -189,7 +192,7 @@ namespace Avalonia.Controls /// /// TickBar will use ReservedSpaceProperty for left and right spacing (for horizontal orientation) or - /// tob and bottom spacing (for vertical orienation). + /// top and bottom spacing (for vertical orienation). /// The space on both sides of TickBar is half of specified ReservedSpace. /// This property has type of . /// @@ -201,7 +204,7 @@ namespace Avalonia.Controls /// /// Draw ticks. - /// Ticks can be draw in 8 diffrent ways depends on Placment property and IsDirectionReversed property. + /// Ticks can be draw in 8 different ways depends on Placement property and IsDirectionReversed property. /// /// This function also draw selection-tick(s) if IsSelectionRangeEnabled is 'true' and /// SelectionStart and SelectionEnd are valid. @@ -211,9 +214,7 @@ namespace Avalonia.Controls /// /// The secondary ticks (all other ticks, including selection-tics) height will be 75% of TickBar's render size. /// - /// Brush that use to fill ticks is specified by Shape.Fill property. - /// - /// Pen that use to draw ticks is specified by Shape.Pen property. + /// Brush that use to fill ticks is specified by Fill property. /// public override void Render(DrawingContext dc) { @@ -222,7 +223,6 @@ namespace Avalonia.Controls var tickLen = 0.0d; // Height for Primary Tick (for Mininum and Maximum value) var tickLen2 = 0.0d; // Height for Secondary Tick var logicalToPhysical = 1.0; - var progression = 1.0d; var startPoint = new Point(); var endPoint = new Point(); var rSpace = Orientation == Orientation.Horizontal ? ReservedSpace.Width : ReservedSpace.Height; @@ -242,7 +242,6 @@ namespace Avalonia.Controls startPoint = new Point(halfReservedSpace, size.Height); endPoint = new Point(halfReservedSpace + size.Width, size.Height); logicalToPhysical = size.Width / range; - progression = 1; break; case TickBarPlacement.Bottom: @@ -255,7 +254,6 @@ namespace Avalonia.Controls startPoint = new Point(halfReservedSpace, 0d); endPoint = new Point(halfReservedSpace + size.Width, 0d); logicalToPhysical = size.Width / range; - progression = 1; break; case TickBarPlacement.Left: @@ -269,7 +267,6 @@ namespace Avalonia.Controls startPoint = new Point(size.Width, size.Height + halfReservedSpace); endPoint = new Point(size.Width, halfReservedSpace); logicalToPhysical = size.Height / range * -1; - progression = -1; break; case TickBarPlacement.Right: @@ -282,7 +279,6 @@ namespace Avalonia.Controls startPoint = new Point(0d, size.Height + halfReservedSpace); endPoint = new Point(0d, halfReservedSpace); logicalToPhysical = size.Height / range * -1; - progression = -1; break; }; @@ -291,7 +287,6 @@ namespace Avalonia.Controls // Invert direciton of the ticks if (IsDirectionReversed) { - progression *= -progression; logicalToPhysical *= -1; // swap startPoint & endPoint From 453222d8de6d8ac74361e554dea20b97529369f2 Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Thu, 16 Jul 2020 19:18:40 +0200 Subject: [PATCH 022/344] Fix some comments --- .../Media/TextFormatting/TextFormatterImpl.cs | 302 +++++++++--------- .../Media/TextFormatting/TextLayout.cs | 5 + .../Media/TextFormatting/TextLine.cs | 40 ++- .../Media/TextFormatting/TextLineImpl.cs | 3 +- .../Media/TextFormatting/TextRunProperties.cs | 7 +- 5 files changed, 184 insertions(+), 173 deletions(-) diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs index 061949a5c9..9318fcc68e 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs +++ b/src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs @@ -41,6 +41,156 @@ namespace Avalonia.Media.TextFormatting return textLine; } + /// + /// Measures the number of characters that fits into available width. + /// + /// The text run. + /// The available width. + /// + internal static int MeasureCharacters(ShapedTextCharacters textCharacters, double availableWidth) + { + var glyphRun = textCharacters.GlyphRun; + + if (glyphRun.Bounds.Width < availableWidth) + { + return glyphRun.Characters.Length; + } + + var glyphCount = 0; + + var currentWidth = 0.0; + + if (glyphRun.GlyphAdvances.IsEmpty) + { + var glyphTypeface = glyphRun.GlyphTypeface; + + for (var i = 0; i < glyphRun.GlyphClusters.Length; i++) + { + var glyph = glyphRun.GlyphIndices[i]; + + var advance = glyphTypeface.GetGlyphAdvance(glyph) * glyphRun.Scale; + + if (currentWidth + advance > availableWidth) + { + break; + } + + currentWidth += advance; + + glyphCount++; + } + } + else + { + foreach (var advance in glyphRun.GlyphAdvances) + { + if (currentWidth + advance > availableWidth) + { + break; + } + + currentWidth += advance; + + glyphCount++; + } + } + + if (glyphCount == glyphRun.GlyphIndices.Length) + { + return glyphRun.Characters.Length; + } + + if (glyphRun.GlyphClusters.IsEmpty) + { + return glyphCount; + } + + var firstCluster = glyphRun.GlyphClusters[0]; + + var lastCluster = glyphRun.GlyphClusters[glyphCount]; + + return lastCluster - firstCluster; + } + + /// + /// Split a sequence of runs into two segments at specified length. + /// + /// The text run's. + /// The length to split at. + /// The split text runs. + internal static SplitTextRunsResult SplitTextRuns(IReadOnlyList textRuns, int length) + { + var currentLength = 0; + + for (var i = 0; i < textRuns.Count; i++) + { + var currentRun = textRuns[i]; + + if (currentLength + currentRun.GlyphRun.Characters.Length < length) + { + currentLength += currentRun.GlyphRun.Characters.Length; + continue; + } + + var firstCount = currentRun.GlyphRun.Characters.Length >= 1 ? i + 1 : i; + + var first = new ShapedTextCharacters[firstCount]; + + if (firstCount > 1) + { + for (var j = 0; j < i; j++) + { + first[j] = textRuns[j]; + } + } + + var secondCount = textRuns.Count - firstCount; + + if (currentLength + currentRun.GlyphRun.Characters.Length == length) + { + var second = new ShapedTextCharacters[secondCount]; + + var offset = currentRun.GlyphRun.Characters.Length > 1 ? 1 : 0; + + if (secondCount > 0) + { + for (var j = 0; j < secondCount; j++) + { + second[j] = textRuns[i + j + offset]; + } + } + + first[i] = currentRun; + + return new SplitTextRunsResult(first, second); + } + else + { + secondCount++; + + var second = new ShapedTextCharacters[secondCount]; + + if (secondCount > 0) + { + for (var j = 1; j < secondCount; j++) + { + second[j] = textRuns[i + j]; + } + } + + var split = currentRun.Split(length - currentLength); + + first[i] = split.First; + + second[0] = split.Second; + + return new SplitTextRunsResult(first, second); + } + } + + return new SplitTextRunsResult(textRuns, null); + } + /// /// Fetches text runs. /// @@ -188,7 +338,7 @@ namespace Avalonia.Media.TextFormatting if (currentWidth + currentRun.GlyphRun.Bounds.Width > availableWidth) { - var measuredLength = MeasureText(currentRun, paragraphWidth - currentWidth); + var measuredLength = MeasureCharacters(currentRun, paragraphWidth - currentWidth); var breakFound = false; @@ -256,77 +406,6 @@ namespace Avalonia.Media.TextFormatting TextLineMetrics.Create(textRuns, textRange, paragraphWidth, paragraphProperties)); } - /// - /// Measures the number of characters that fits into available width. - /// - /// The text run. - /// The available width. - /// - internal static int MeasureText(ShapedTextCharacters textCharacters, double availableWidth) - { - var glyphRun = textCharacters.GlyphRun; - - if (glyphRun.Bounds.Width < availableWidth) - { - return glyphRun.Characters.Length; - } - - var glyphCount = 0; - - var currentWidth = 0.0; - - if (glyphRun.GlyphAdvances.IsEmpty) - { - var glyphTypeface = glyphRun.GlyphTypeface; - - for (var i = 0; i < glyphRun.GlyphClusters.Length; i++) - { - var glyph = glyphRun.GlyphIndices[i]; - - var advance = glyphTypeface.GetGlyphAdvance(glyph) * glyphRun.Scale; - - if (currentWidth + advance > availableWidth) - { - break; - } - - currentWidth += advance; - - glyphCount++; - } - } - else - { - foreach (var advance in glyphRun.GlyphAdvances) - { - if (currentWidth + advance > availableWidth) - { - break; - } - - currentWidth += advance; - - glyphCount++; - } - } - - if (glyphCount == glyphRun.GlyphIndices.Length) - { - return glyphRun.Characters.Length; - } - - if (glyphRun.GlyphClusters.IsEmpty) - { - return glyphCount; - } - - var firstCluster = glyphRun.GlyphClusters[0]; - - var lastCluster = glyphRun.GlyphClusters[glyphCount]; - - return lastCluster - firstCluster; - } - /// /// Gets the text range that is covered by the text runs. /// @@ -353,85 +432,6 @@ namespace Avalonia.Media.TextFormatting return new TextRange(start, end - start); } - /// - /// Split a sequence of runs into two segments at specified length. - /// - /// The text run's. - /// The length to split at. - /// The split text runs. - internal static SplitTextRunsResult SplitTextRuns(IReadOnlyList textRuns, int length) - { - var currentLength = 0; - - for (var i = 0; i < textRuns.Count; i++) - { - var currentRun = textRuns[i]; - - if (currentLength + currentRun.GlyphRun.Characters.Length < length) - { - currentLength += currentRun.GlyphRun.Characters.Length; - continue; - } - - var firstCount = currentRun.GlyphRun.Characters.Length >= 1 ? i + 1 : i; - - var first = new ShapedTextCharacters[firstCount]; - - if (firstCount > 1) - { - for (var j = 0; j < i; j++) - { - first[j] = textRuns[j]; - } - } - - var secondCount = textRuns.Count - firstCount; - - if (currentLength + currentRun.GlyphRun.Characters.Length == length) - { - var second = new ShapedTextCharacters[secondCount]; - - var offset = currentRun.GlyphRun.Characters.Length > 1 ? 1 : 0; - - if (secondCount > 0) - { - for (var j = 0; j < secondCount; j++) - { - second[j] = textRuns[i + j + offset]; - } - } - - first[i] = currentRun; - - return new SplitTextRunsResult(first, second); - } - else - { - secondCount++; - - var second = new ShapedTextCharacters[secondCount]; - - if (secondCount > 0) - { - for (var j = 1; j < secondCount; j++) - { - second[j] = textRuns[i + j]; - } - } - - var split = currentRun.Split(length - currentLength); - - first[i] = split.First; - - second[0] = split.Second; - - return new SplitTextRunsResult(first, second); - } - } - - return new SplitTextRunsResult(textRuns, null); - } - internal readonly struct SplitTextRunsResult { public SplitTextRunsResult(IReadOnlyList first, IReadOnlyList second) diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs index 92db6b69c4..14602a2560 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs +++ b/src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs @@ -268,6 +268,11 @@ namespace Avalonia.Media.TextFormatting } } + /// + /// Gets the for current text trimming mode. + /// + /// The collapsing width. + /// The . private TextCollapsingProperties GetCollapsingProperties(double width) { return _textTrimming switch diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextLine.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextLine.cs index 3e3258f38a..423ca9fb7f 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/TextLine.cs +++ b/src/Avalonia.Visuals/Media/TextFormatting/TextLine.cs @@ -40,8 +40,11 @@ namespace Avalonia.Media.TextFormatting public abstract TextLineBreak LineBreak { get; } /// - /// Client to get a boolean value indicates whether a line has been collapsed + /// Gets a value that indicates whether the line is collapsed. /// + /// + /// true, if the line is collapsed; otherwise, false. + /// public abstract bool HasCollapsed { get; } /// @@ -52,46 +55,49 @@ namespace Avalonia.Media.TextFormatting public abstract void Draw(DrawingContext drawingContext, Point origin); /// - /// Client to collapse the line and get a collapsed line that fits for display + /// Create a collapsed line based on collapsed text properties. /// - /// a list of collapsing properties + /// A list of + /// objects that represent the collapsed text properties. + /// + /// A value that represents a collapsed line that can be displayed. + /// public abstract TextLine Collapse(params TextCollapsingProperties[] collapsingPropertiesList); /// - /// Client to get the character hit corresponding to the specified - /// distance from the beginning of the line. + /// Gets the character hit corresponding to the specified distance from the beginning of the line. /// - /// distance in text flow direction from the beginning of the line - /// The + /// A value that represents the distance from the beginning of the line. + /// The object at the specified distance from the beginning of the line. public abstract CharacterHit GetCharacterHitFromDistance(double distance); /// - /// Client to get the distance from the beginning of the line from the specified + /// Gets the distance from the beginning of the line to the specified character hit. /// . /// - /// of the character to query the distance. - /// Distance in text flow direction from the beginning of the line. + /// The object whose distance you want to query. + /// A that represents the distance from the beginning of the line. public abstract double GetDistanceFromCharacterHit(CharacterHit characterHit); /// - /// Client to get the next for caret navigation. + /// Gets the next character hit for caret navigation. /// /// The current . /// The next . public abstract CharacterHit GetNextCaretCharacterHit(CharacterHit characterHit); /// - /// Client to get the previous character hit for caret navigation + /// Gets the previous character hit for caret navigation. /// - /// the current character hit - /// The previous + /// The current . + /// The previous . public abstract CharacterHit GetPreviousCaretCharacterHit(CharacterHit characterHit); /// - /// Client to get the previous character hit after backspacing + /// Gets the previous character hit after backspacing. /// - /// the current character hit - /// The after backspacing + /// The current . + /// The after backspacing. public abstract CharacterHit GetBackspaceCaretCharacterHit(CharacterHit characterHit); /// diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs index 820c943aea..980b1a2d40 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs +++ b/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs @@ -47,6 +47,7 @@ namespace Avalonia.Media.TextFormatting } } + /// public override TextLine Collapse(params TextCollapsingProperties[] collapsingPropertiesList) { if (collapsingPropertiesList == null || collapsingPropertiesList.Length == 0) @@ -73,7 +74,7 @@ namespace Avalonia.Media.TextFormatting if (currentWidth > availableWidth) { - var measuredLength = TextFormatterImpl.MeasureText(currentRun, availableWidth); + var measuredLength = TextFormatterImpl.MeasureCharacters(currentRun, availableWidth); var currentBreakPosition = 0; diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextRunProperties.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextRunProperties.cs index bbcdfe2d8e..c4f9443c3d 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/TextRunProperties.cs +++ b/src/Avalonia.Visuals/Media/TextFormatting/TextRunProperties.cs @@ -4,12 +4,11 @@ using System.Globalization; namespace Avalonia.Media.TextFormatting { /// - /// Properties that can change from one run to the next, such as typeface or foreground brush. + /// Provides a set of properties, such as typeface or foreground brush, that can be applied to a TextRun object. This is an abstract class. /// /// - /// The client provides a concrete implementation of this abstract run properties class. This - /// allows client to implement their run properties the way that fits with their run formatting - /// store. + /// The text layout client provides a concrete implementation of this abstract class. + /// This enables the client to implement text run properties in a way that corresponds with the associated formatting store. /// public abstract class TextRunProperties : IEquatable { From 856118f21c6ca84a93bd293f0dba14208084a0a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Pedro?= Date: Fri, 17 Jul 2020 06:57:54 +0100 Subject: [PATCH 023/344] Use TextBox text alignment and wrapping in watermark. --- src/Avalonia.Themes.Default/TextBox.xaml | 2 ++ src/Avalonia.Themes.Fluent/TextBox.xaml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/Avalonia.Themes.Default/TextBox.xaml b/src/Avalonia.Themes.Default/TextBox.xaml index 4fb3653e89..6a746dda30 100644 --- a/src/Avalonia.Themes.Default/TextBox.xaml +++ b/src/Avalonia.Themes.Default/TextBox.xaml @@ -40,6 +40,8 @@ Date: Fri, 17 Jul 2020 15:37:44 +0200 Subject: [PATCH 024/344] Correctly compare against text.Length --- src/Avalonia.Visuals/Media/TextFormatting/Unicode/Codepoint.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Visuals/Media/TextFormatting/Unicode/Codepoint.cs b/src/Avalonia.Visuals/Media/TextFormatting/Unicode/Codepoint.cs index 20fe345d93..2f46fdd9d0 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/Unicode/Codepoint.cs +++ b/src/Avalonia.Visuals/Media/TextFormatting/Unicode/Codepoint.cs @@ -112,7 +112,7 @@ namespace Avalonia.Media.TextFormatting.Unicode { count = 1; - if (index > text.End) + if (index > text.Length) { return ReplacementCodepoint; } From a6c0968218f21302011d4959fda0c4a05d124cdc Mon Sep 17 00:00:00 2001 From: Benedikt Stebner Date: Fri, 17 Jul 2020 17:34:05 +0200 Subject: [PATCH 025/344] Correctly check for text.Length --- src/Skia/Avalonia.Skia/TextShaperImpl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Skia/Avalonia.Skia/TextShaperImpl.cs b/src/Skia/Avalonia.Skia/TextShaperImpl.cs index ffe1175567..558e96b097 100644 --- a/src/Skia/Avalonia.Skia/TextShaperImpl.cs +++ b/src/Skia/Avalonia.Skia/TextShaperImpl.cs @@ -82,7 +82,7 @@ namespace Avalonia.Skia if (codepoint.IsBreakChar) { - if (i < text.End) + if (i < text.Length) { var nextCodepoint = Codepoint.ReadAt(text, i + 1, out _); From 718a50ccd8ff8d1eb12e0629c4da5209a7538a88 Mon Sep 17 00:00:00 2001 From: Benedikt Stebner Date: Fri, 17 Jul 2020 18:28:25 +0200 Subject: [PATCH 026/344] Fix FillBuffer --- src/Skia/Avalonia.Skia/TextShaperImpl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Skia/Avalonia.Skia/TextShaperImpl.cs b/src/Skia/Avalonia.Skia/TextShaperImpl.cs index 558e96b097..b0384a1fdf 100644 --- a/src/Skia/Avalonia.Skia/TextShaperImpl.cs +++ b/src/Skia/Avalonia.Skia/TextShaperImpl.cs @@ -82,7 +82,7 @@ namespace Avalonia.Skia if (codepoint.IsBreakChar) { - if (i < text.Length) + if (i + 1 < text.Length) { var nextCodepoint = Codepoint.ReadAt(text, i + 1, out _); From 05154391fb39d430ae0c0df1344feea111ef54e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Pedro?= Date: Tue, 14 Jul 2020 19:29:40 +0100 Subject: [PATCH 027/344] Fixed item type inference in compiled bindings. --- ...valoniaXamlIlDataContextTypeTransformer.cs | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 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 5a0d6bac8d..241976241f 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs @@ -1,11 +1,6 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using System.Text; -using Avalonia.Markup.Parsers; -using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers; -using Avalonia.Utilities; using XamlX; using XamlX.Ast; using XamlX.Transform; @@ -129,12 +124,13 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers if (itemsCollectionType != null) { - var elementType = itemsCollectionType - .GetAllInterfaces() - .FirstOrDefault(i => - i.GenericTypeDefinition?.Equals(context.Configuration.WellKnownTypes.IEnumerableT) == true) - .GenericArguments[0]; - return new AvaloniaXamlIlDataContextTypeMetadataNode(on, elementType); + foreach (var i in GetAllInterfacesIncludingSelf(itemsCollectionType)) + { + if (i.GenericTypeDefinition?.Equals(context.Configuration.WellKnownTypes.IEnumerableT) == true) + { + return new AvaloniaXamlIlDataContextTypeMetadataNode(on, i.GenericArguments[0]); + } + } } // We can't infer the collection type and the currently calculated type is definitely wrong. // Notify the user that we were unable to infer the data context type if they use a compiled binding. @@ -165,6 +161,15 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers return new AvaloniaXamlIlUninferrableDataContextMetadataNode(on); } + + private static IEnumerable GetAllInterfacesIncludingSelf(IXamlType type) + { + if (type.IsInterface) + yield return type; + + foreach (var i in type.GetAllInterfaces()) + yield return i; + } } [DebuggerDisplay("DataType = {DataContextType}")] From c414e26cf67a60c625a8f925cd87f303b162fb9d Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Sun, 19 Jul 2020 00:15:08 +0200 Subject: [PATCH 028/344] Ensure that TryParse won't throw. --- src/Avalonia.Visuals/Media/Color.cs | 13 ++++++++---- .../Media/ColorTests.cs | 20 +++++++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.Visuals/Media/Color.cs b/src/Avalonia.Visuals/Media/Color.cs index 052ee5e1b7..40515423dd 100644 --- a/src/Avalonia.Visuals/Media/Color.cs +++ b/src/Avalonia.Visuals/Media/Color.cs @@ -89,6 +89,11 @@ namespace Avalonia.Media /// The . public static Color Parse(string s) { + if (s is null) + { + throw new ArgumentNullException(nameof(s)); + } + if (TryParse(s, out Color color)) { return color; @@ -120,14 +125,16 @@ namespace Avalonia.Media /// The status of the operation. public static bool TryParse(string s, out Color color) { + color = default; + if (s == null) { - throw new ArgumentNullException(nameof(s)); + return false; } if (s.Length == 0) { - throw new FormatException(); + return false; } if (s[0] == '#' && TryParseInternal(s.AsSpan(), out color)) @@ -144,8 +151,6 @@ namespace Avalonia.Media return true; } - color = default; - return false; } diff --git a/tests/Avalonia.Visuals.UnitTests/Media/ColorTests.cs b/tests/Avalonia.Visuals.UnitTests/Media/ColorTests.cs index f3f3c9a4ca..d68c2fd5fd 100644 --- a/tests/Avalonia.Visuals.UnitTests/Media/ColorTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/Media/ColorTests.cs @@ -179,5 +179,25 @@ namespace Avalonia.Visuals.UnitTests.Media { Assert.False(Color.TryParse("#ff808g80", out _)); } + + [Fact] + public void Parse_Throws_ArgumentNullException_For_Null_Input() + { + Assert.Throws(() => Color.Parse((string)null)); + } + + [Fact] + public void Parse_Throws_FormatException_For_Invalid_Input() + { + Assert.Throws(() => Color.Parse(string.Empty)); + } + + [Theory] + [InlineData("")] + [InlineData(null)] + public void TryParse_Returns_False_For_Invalid_Input(string input) + { + Assert.False(Color.TryParse(input, out _)); + } } } From 50925b988e04b1cb06e906bd81d9b3760c004d49 Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Sun, 19 Jul 2020 00:19:23 +0200 Subject: [PATCH 029/344] Use is check. --- src/Avalonia.Visuals/Media/Color.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Visuals/Media/Color.cs b/src/Avalonia.Visuals/Media/Color.cs index 40515423dd..16b4f90d57 100644 --- a/src/Avalonia.Visuals/Media/Color.cs +++ b/src/Avalonia.Visuals/Media/Color.cs @@ -127,7 +127,7 @@ namespace Avalonia.Media { color = default; - if (s == null) + if (s is null) { return false; } From 09099c1234bb5fdf0285d3855bf8c515ae056184 Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Sun, 19 Jul 2020 14:50:29 +0200 Subject: [PATCH 030/344] Fix text wrapping for fluent TextBox --- src/Avalonia.Controls/TextBox.cs | 2 +- src/Avalonia.Themes.Fluent/TextBox.xaml | 105 +++++++++----------- src/Skia/Avalonia.Skia/FormattedTextImpl.cs | 2 +- 3 files changed, 51 insertions(+), 58 deletions(-) diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index 394699ce64..87a674fabd 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -134,7 +134,7 @@ namespace Avalonia.Controls { if (acceptsReturn) { - return wrapping == TextWrapping.NoWrap ? + return wrapping != TextWrapping.Wrap ? ScrollBarVisibility.Auto : ScrollBarVisibility.Disabled; } diff --git a/src/Avalonia.Themes.Fluent/TextBox.xaml b/src/Avalonia.Themes.Fluent/TextBox.xaml index 278cde934c..0327e776e3 100644 --- a/src/Avalonia.Themes.Fluent/TextBox.xaml +++ b/src/Avalonia.Themes.Fluent/TextBox.xaml @@ -10,73 +10,65 @@ - - - + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - + - - - - - - + + + + + + + diff --git a/src/Skia/Avalonia.Skia/FormattedTextImpl.cs b/src/Skia/Avalonia.Skia/FormattedTextImpl.cs index d1f8d6a779..5e630e54a6 100644 --- a/src/Skia/Avalonia.Skia/FormattedTextImpl.cs +++ b/src/Skia/Avalonia.Skia/FormattedTextImpl.cs @@ -570,7 +570,7 @@ namespace Avalonia.Skia float constraint = -1; - if (_wrapping != TextWrapping.NoWrap) + if (_wrapping == TextWrapping.Wrap) { constraint = widthConstraint <= 0 ? MAX_LINE_WIDTH : widthConstraint; if (constraint > MAX_LINE_WIDTH) From 2ede354bbc7268f39c733342212a7730e976a7e0 Mon Sep 17 00:00:00 2001 From: Lorenzo Delana Date: Mon, 20 Jul 2020 14:53:19 +0200 Subject: [PATCH 031/344] fix X11 XDestroyWindow crash --- src/Avalonia.X11/X11Window.cs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 2a13999e8d..1f1f31db0a 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -760,11 +760,7 @@ namespace Avalonia.X11 public void Dispose() { - if (_handle != IntPtr.Zero) - { - XDestroyWindow(_x11.Display, _handle); - Cleanup(); - } + Cleanup(); } void Cleanup() @@ -787,8 +783,7 @@ namespace Avalonia.X11 } if (_useRenderWindow && _renderHandle != IntPtr.Zero) - { - XDestroyWindow(_x11.Display, _renderHandle); + { _renderHandle = IntPtr.Zero; } } From c5edf9bc5da4e1dabad5d5a9f3cd8b078bd254d2 Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Mon, 20 Jul 2020 18:37:11 +0200 Subject: [PATCH 032/344] Initial --- .../Media/TextFormatting/TextLineImpl.cs | 20 ++++-- .../Media/TextFormatting/TextLineTests.cs | 62 +++++++++++++++++-- 2 files changed, 71 insertions(+), 11 deletions(-) diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs index 980b1a2d40..f73a7be759 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs +++ b/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs @@ -181,7 +181,7 @@ namespace Avalonia.Media.TextFormatting return nextCharacterHit; } - return new CharacterHit(TextRange.End); // Can't move, we're after the last character + return characterHit; // Can't move, we're after the last character } /// @@ -192,7 +192,7 @@ namespace Avalonia.Media.TextFormatting return previousCharacterHit; } - return new CharacterHit(TextRange.Start); // Can't move, we're before the first character + return characterHit; // Can't move, we're before the first character } /// @@ -247,9 +247,13 @@ namespace Avalonia.Media.TextFormatting { var run = _textRuns[runIndex]; - nextCharacterHit = run.GlyphRun.FindNearestCharacterHit(characterHit.FirstCharacterIndex + characterHit.TrailingLength, out _); + var foundCharacterHit = run.GlyphRun.FindNearestCharacterHit(characterHit.FirstCharacterIndex + characterHit.TrailingLength, out _); - if (codepointIndex <= nextCharacterHit.FirstCharacterIndex + nextCharacterHit.TrailingLength) + nextCharacterHit = characterHit.TrailingLength != 0 ? + foundCharacterHit : + new CharacterHit(foundCharacterHit.FirstCharacterIndex + foundCharacterHit.TrailingLength); + + if (nextCharacterHit.FirstCharacterIndex > characterHit.FirstCharacterIndex) { return true; } @@ -283,9 +287,13 @@ namespace Avalonia.Media.TextFormatting { var run = _textRuns[runIndex]; - previousCharacterHit = run.GlyphRun.FindNearestCharacterHit(characterHit.FirstCharacterIndex - 1, out _); + var foundCharacterHit = run.GlyphRun.FindNearestCharacterHit(characterHit.FirstCharacterIndex - 1, out _); + + previousCharacterHit = characterHit.TrailingLength != 0 ? + foundCharacterHit : + new CharacterHit(foundCharacterHit.FirstCharacterIndex); - if (previousCharacterHit.FirstCharacterIndex < codepointIndex) + if (previousCharacterHit.FirstCharacterIndex < characterHit.FirstCharacterIndex) { return true; } diff --git a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs index f0951c61d3..09cbf3bf08 100644 --- a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs +++ b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs @@ -31,12 +31,37 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting var nextCharacterHit = new CharacterHit(0); - for (var i = 1; i < clusters.Length; i++) + for (var i = 0; i < clusters.Length; i++) { + Assert.Equal(clusters[i], nextCharacterHit.FirstCharacterIndex); + nextCharacterHit = textLine.GetNextCaretCharacterHit(nextCharacterHit); + } + + var lastCharacterHit = nextCharacterHit; + + nextCharacterHit = textLine.GetNextCaretCharacterHit(lastCharacterHit); + + Assert.Equal(lastCharacterHit.FirstCharacterIndex, nextCharacterHit.FirstCharacterIndex); + + Assert.Equal(lastCharacterHit.TrailingLength, nextCharacterHit.TrailingLength); + + nextCharacterHit = new CharacterHit(0, clusters[1] - clusters[0]); - Assert.Equal(clusters[i], nextCharacterHit.FirstCharacterIndex + nextCharacterHit.TrailingLength); + for (var i = 0; i < clusters.Length; i++) + { + Assert.Equal(clusters[i], nextCharacterHit.FirstCharacterIndex); + + nextCharacterHit = textLine.GetNextCaretCharacterHit(nextCharacterHit); } + + lastCharacterHit = nextCharacterHit; + + nextCharacterHit = textLine.GetNextCaretCharacterHit(lastCharacterHit); + + Assert.Equal(lastCharacterHit.FirstCharacterIndex, nextCharacterHit.FirstCharacterIndex); + + Assert.Equal(lastCharacterHit.TrailingLength, nextCharacterHit.TrailingLength); } } @@ -60,14 +85,41 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting var clusters = textLine.TextRuns.Cast().SelectMany(x => x.GlyphRun.GlyphClusters) .ToArray(); - var previousCharacterHit = new CharacterHit(clusters[^1]); + var previousCharacterHit = new CharacterHit(text.Length); - for (var i = clusters.Length - 2; i > 0; i--) + for (var i = clusters.Length - 1; i >= 0; i--) { previousCharacterHit = textLine.GetPreviousCaretCharacterHit(previousCharacterHit); - Assert.Equal(clusters[i], previousCharacterHit.FirstCharacterIndex); + Assert.Equal(clusters[i], + previousCharacterHit.FirstCharacterIndex + previousCharacterHit.TrailingLength); } + + var firstCharacterHit = previousCharacterHit; + + previousCharacterHit = textLine.GetPreviousCaretCharacterHit(firstCharacterHit); + + Assert.Equal(firstCharacterHit.FirstCharacterIndex, previousCharacterHit.FirstCharacterIndex); + + Assert.Equal(firstCharacterHit.TrailingLength, previousCharacterHit.TrailingLength); + + previousCharacterHit = new CharacterHit(clusters[^1], text.Length - clusters[^1]); + + for (var i = clusters.Length - 1; i > 0; i--) + { + previousCharacterHit = textLine.GetPreviousCaretCharacterHit(previousCharacterHit); + + Assert.Equal(clusters[i], + previousCharacterHit.FirstCharacterIndex + previousCharacterHit.TrailingLength); + } + + firstCharacterHit = previousCharacterHit; + + previousCharacterHit = textLine.GetPreviousCaretCharacterHit(firstCharacterHit); + + Assert.Equal(firstCharacterHit.FirstCharacterIndex, previousCharacterHit.FirstCharacterIndex); + + Assert.Equal(firstCharacterHit.TrailingLength, previousCharacterHit.TrailingLength); } } From 8c331534a9071a4b95e927cf9805ad5b455963c1 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Mon, 20 Jul 2020 15:44:19 -0300 Subject: [PATCH 033/344] fix nre on osx when tooltip closes. --- src/Avalonia.Native/WindowImplBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Native/WindowImplBase.cs b/src/Avalonia.Native/WindowImplBase.cs index f916e95d7c..88956e41e1 100644 --- a/src/Avalonia.Native/WindowImplBase.cs +++ b/src/Avalonia.Native/WindowImplBase.cs @@ -432,7 +432,7 @@ namespace Avalonia.Native TransparencyLevel = transparencyLevel; - _native.SetBlurEnabled(TransparencyLevel >= WindowTransparencyLevel.Blur); + _native?.SetBlurEnabled(TransparencyLevel >= WindowTransparencyLevel.Blur); TransparencyLevelChanged?.Invoke(TransparencyLevel); } } From 0148106f545a3afa3b4b87b3f7a731f04a54d9ea Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Mon, 20 Jul 2020 16:27:26 -0300 Subject: [PATCH 034/344] Seperate RenderScaling from DesktopScaling. --- .../Platform/SkiaPlatform/TopLevelImpl.cs | 2 +- .../Offscreen/OffscreenTopLevelImpl.cs | 2 +- .../Platform/ITopLevelImpl.cs | 6 +-- .../Platform/IWindowBaseImpl.cs | 5 +++ .../ManagedPopupPositionerPopupImplHelper.cs | 4 +- src/Avalonia.Controls/TopLevel.cs | 4 +- src/Avalonia.Controls/Window.cs | 2 +- .../Remote/PreviewerWindowImpl.cs | 1 + src/Avalonia.DesignerSupport/Remote/Stubs.cs | 3 +- src/Avalonia.Headless/HeadlessWindowImpl.cs | 9 +++-- ...sxManagedPopupPositionerPopupImplHelper.cs | 15 -------- src/Avalonia.Native/PopupImpl.cs | 2 +- src/Avalonia.Native/WindowImplBase.cs | 8 ++-- src/Avalonia.X11/X11NativeControlHost.cs | 4 +- src/Avalonia.X11/X11Window.cs | 38 ++++++++++--------- .../FramebufferToplevelImpl.cs | 4 +- .../Wpf/WpfTopLevelImpl.cs | 6 +-- src/Windows/Avalonia.Win32/PopupImpl.cs | 2 +- .../Avalonia.Win32/Win32NativeControlHost.cs | 4 +- .../Avalonia.Win32/WindowImpl.AppWndProc.cs | 14 +++---- .../WindowImpl.CustomCaptionProc.cs | 2 +- src/Windows/Avalonia.Win32/WindowImpl.cs | 28 ++++++++------ src/iOS/Avalonia.iOS/TopLevelImpl.cs | 2 +- .../ContextMenuTests.cs | 2 +- .../DesktopStyleApplicationLifetimeTests.cs | 2 +- .../TopLevelTests.cs | 4 +- .../WindowBaseTests.cs | 10 ++--- .../WindowTests.cs | 14 +++---- .../WindowingPlatformMock.cs | 4 +- tests/Avalonia.LeakTests/ControlTests.cs | 2 +- .../MockWindowingPlatform.cs | 4 +- 31 files changed, 105 insertions(+), 104 deletions(-) delete mode 100644 src/Avalonia.Native/OsxManagedPopupPositionerPopupImplHelper.cs diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs index 69fd2a9f13..71dce93ce7 100644 --- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs +++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs @@ -126,7 +126,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform _view.Visibility = ViewStates.Visible; } - public double Scaling => 1; + public double RenderScaling => 1; void Draw() { diff --git a/src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevelImpl.cs b/src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevelImpl.cs index f8bd2878d9..522103c7bd 100644 --- a/src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevelImpl.cs +++ b/src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevelImpl.cs @@ -35,7 +35,7 @@ namespace Avalonia.Controls.Embedding.Offscreen } } - public double Scaling + public double RenderScaling { get { return _scaling; } set diff --git a/src/Avalonia.Controls/Platform/ITopLevelImpl.cs b/src/Avalonia.Controls/Platform/ITopLevelImpl.cs index 0d77cbf802..7514f214aa 100644 --- a/src/Avalonia.Controls/Platform/ITopLevelImpl.cs +++ b/src/Avalonia.Controls/Platform/ITopLevelImpl.cs @@ -23,10 +23,10 @@ namespace Avalonia.Platform Size ClientSize { get; } /// - /// Gets the scaling factor for the toplevel. + /// Gets the scaling factor for the toplevel. This is used for rendering. /// - double Scaling { get; } - + double RenderScaling { get; } + /// /// The list of native platform's surfaces that can be consumed by rendering subsystems. /// diff --git a/src/Avalonia.Controls/Platform/IWindowBaseImpl.cs b/src/Avalonia.Controls/Platform/IWindowBaseImpl.cs index b190c4f2e7..ecaf87d1ed 100644 --- a/src/Avalonia.Controls/Platform/IWindowBaseImpl.cs +++ b/src/Avalonia.Controls/Platform/IWindowBaseImpl.cs @@ -13,6 +13,11 @@ namespace Avalonia.Platform /// Hides the window. /// void Hide(); + + /// + /// Gets the scaling factor for Window positioning and sizing. + /// + double DesktopScaling { get; } /// /// Gets the position of the window in device pixels. diff --git a/src/Avalonia.Controls/Primitives/PopupPositioning/ManagedPopupPositionerPopupImplHelper.cs b/src/Avalonia.Controls/Primitives/PopupPositioning/ManagedPopupPositionerPopupImplHelper.cs index b0e3d1ab08..91ed5d975d 100644 --- a/src/Avalonia.Controls/Primitives/PopupPositioning/ManagedPopupPositionerPopupImplHelper.cs +++ b/src/Avalonia.Controls/Primitives/PopupPositioning/ManagedPopupPositionerPopupImplHelper.cs @@ -40,9 +40,9 @@ namespace Avalonia.Controls.Primitives.PopupPositioning public void MoveAndResize(Point devicePoint, Size virtualSize) { - _moveResize(new PixelPoint((int)devicePoint.X, (int)devicePoint.Y), virtualSize, _parent.Scaling); + _moveResize(new PixelPoint((int)devicePoint.X, (int)devicePoint.Y), virtualSize, _parent.RenderScaling); } - public virtual double Scaling => _parent.Scaling; + public virtual double Scaling => _parent.DesktopScaling; } } diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs index 611f0c9290..3d24f60463 100644 --- a/src/Avalonia.Controls/TopLevel.cs +++ b/src/Avalonia.Controls/TopLevel.cs @@ -280,10 +280,10 @@ namespace Avalonia.Controls } /// - double ILayoutRoot.LayoutScaling => PlatformImpl?.Scaling ?? 1; + double ILayoutRoot.LayoutScaling => PlatformImpl?.RenderScaling ?? 1; /// - double IRenderRoot.RenderScaling => PlatformImpl?.Scaling ?? 1; + double IRenderRoot.RenderScaling => PlatformImpl?.RenderScaling ?? 1; IStyleHost IStyleHost.StylingParent => _globalStyles; diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 18d8c89f49..90e5c22c45 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -818,7 +818,7 @@ namespace Avalonia.Controls private void SetWindowStartupLocation(IWindowBaseImpl owner = null) { - var scaling = owner?.Scaling ?? PlatformImpl?.Scaling ?? 1; + var scaling = owner?.DesktopScaling ?? PlatformImpl?.DesktopScaling ?? 1; // TODO: We really need non-client size here. var rect = new PixelRect( diff --git a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs index dce24df9d9..25c26be91e 100644 --- a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs +++ b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs @@ -36,6 +36,7 @@ namespace Avalonia.DesignerSupport.Remote { } + public double DesktopScaling => 1.0; public PixelPoint Position { get; set; } public Action PositionChanged { get; set; } public Action Deactivated { get; set; } diff --git a/src/Avalonia.DesignerSupport/Remote/Stubs.cs b/src/Avalonia.DesignerSupport/Remote/Stubs.cs index 168cdbc03f..f377b1bcd1 100644 --- a/src/Avalonia.DesignerSupport/Remote/Stubs.cs +++ b/src/Avalonia.DesignerSupport/Remote/Stubs.cs @@ -21,7 +21,8 @@ namespace Avalonia.DesignerSupport.Remote public IPlatformHandle Handle { get; } public Size MaxAutoSizeHint { get; } public Size ClientSize { get; } - public double Scaling { get; } = 1.0; + public double RenderScaling { get; } = 1.0; + public double DesktopScaling => 1.0; public IEnumerable Surfaces { get; } public Action Input { get; set; } public Action Paint { get; set; } diff --git a/src/Avalonia.Headless/HeadlessWindowImpl.cs b/src/Avalonia.Headless/HeadlessWindowImpl.cs index 5bd46b6714..8f4fa5e304 100644 --- a/src/Avalonia.Headless/HeadlessWindowImpl.cs +++ b/src/Avalonia.Headless/HeadlessWindowImpl.cs @@ -41,7 +41,8 @@ namespace Avalonia.Headless } public Size ClientSize { get; set; } - public double Scaling { get; } = 1; + public double RenderScaling { get; } = 1; + public double DesktopScaling => RenderScaling; public IEnumerable Surfaces { get; } public Action Input { get; set; } public Action Paint { get; set; } @@ -62,9 +63,9 @@ namespace Avalonia.Headless public IInputRoot InputRoot { get; set; } - public Point PointToClient(PixelPoint point) => point.ToPoint(Scaling); + public Point PointToClient(PixelPoint point) => point.ToPoint(RenderScaling); - public PixelPoint PointToScreen(Point point) => PixelPoint.FromPoint(point, Scaling); + public PixelPoint PointToScreen(Point point) => PixelPoint.FromPoint(point, RenderScaling); public void SetCursor(IPlatformHandle cursor) { @@ -201,7 +202,7 @@ namespace Avalonia.Headless public ILockedFramebuffer Lock() { - var bmp = new WriteableBitmap(PixelSize.FromSize(ClientSize, Scaling), new Vector(96, 96) * Scaling); + var bmp = new WriteableBitmap(PixelSize.FromSize(ClientSize, RenderScaling), new Vector(96, 96) * RenderScaling); var fb = bmp.Lock(); return new FramebufferProxy(fb, () => { diff --git a/src/Avalonia.Native/OsxManagedPopupPositionerPopupImplHelper.cs b/src/Avalonia.Native/OsxManagedPopupPositionerPopupImplHelper.cs deleted file mode 100644 index 8aa9b1a122..0000000000 --- a/src/Avalonia.Native/OsxManagedPopupPositionerPopupImplHelper.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Avalonia.Controls.Primitives.PopupPositioning; -using Avalonia.Platform; - -namespace Avalonia.Native -{ - class OsxManagedPopupPositionerPopupImplHelper : ManagedPopupPositionerPopupImplHelper - { - public OsxManagedPopupPositionerPopupImplHelper(IWindowBaseImpl parent, MoveResizeDelegate moveResize) : base(parent, moveResize) - { - - } - - public override double Scaling => 1; - } -} diff --git a/src/Avalonia.Native/PopupImpl.cs b/src/Avalonia.Native/PopupImpl.cs index b0da5fdc43..2d246e08d2 100644 --- a/src/Avalonia.Native/PopupImpl.cs +++ b/src/Avalonia.Native/PopupImpl.cs @@ -26,7 +26,7 @@ namespace Avalonia.Native var context = _opts.UseGpu ? glFeature?.DeferredContext : null; Init(factory.CreatePopup(e, context?.Context), factory.CreateScreens(), context); } - PopupPositioner = new ManagedPopupPositioner(new OsxManagedPopupPositionerPopupImplHelper(parent, MoveResize)); + PopupPositioner = new ManagedPopupPositioner(new ManagedPopupPositionerPopupImplHelper(parent, MoveResize)); } private void MoveResize(PixelPoint position, Size size, double scaling) diff --git a/src/Avalonia.Native/WindowImplBase.cs b/src/Avalonia.Native/WindowImplBase.cs index f916e95d7c..42eecc36ea 100644 --- a/src/Avalonia.Native/WindowImplBase.cs +++ b/src/Avalonia.Native/WindowImplBase.cs @@ -81,7 +81,7 @@ namespace Avalonia.Native _glSurface = new GlPlatformSurface(window, _glContext); Screen = new ScreenImpl(screens); _savedLogicalSize = ClientSize; - _savedScaling = Scaling; + _savedScaling = RenderScaling; _nativeControlHost = new NativeControlHostImpl(_native.CreateNativeControlHost()); var monitor = Screen.AllScreens.OrderBy(x => x.PixelDensity) @@ -369,7 +369,9 @@ namespace Avalonia.Native _native.SetTopMost(value); } - public double Scaling => _native?.GetScaling() ?? 1; + public double RenderScaling => _native?.GetScaling() ?? 1; + + public double DesktopScaling => 1; public Action Deactivated { get; set; } public Action Activated { get; set; } @@ -432,7 +434,7 @@ namespace Avalonia.Native TransparencyLevel = transparencyLevel; - _native.SetBlurEnabled(TransparencyLevel >= WindowTransparencyLevel.Blur); + _native?.SetBlurEnabled(TransparencyLevel >= WindowTransparencyLevel.Blur); TransparencyLevelChanged?.Invoke(TransparencyLevel); } } diff --git a/src/Avalonia.X11/X11NativeControlHost.cs b/src/Avalonia.X11/X11NativeControlHost.cs index 23fb27f72b..6c4eb81c84 100644 --- a/src/Avalonia.X11/X11NativeControlHost.cs +++ b/src/Avalonia.X11/X11NativeControlHost.cs @@ -167,7 +167,7 @@ namespace Avalonia.X11 XUnmapWindow(_display, _holder.Handle); } - size *= _attachedTo.Window.Scaling; + size *= _attachedTo.Window.RenderScaling; XResizeWindow(_display, _child.Handle, Math.Max(1, (int)size.Width), Math.Max(1, (int)size.Height)); } @@ -179,7 +179,7 @@ namespace Avalonia.X11 CheckDisposed(); if (_attachedTo == null) throw new InvalidOperationException("The control isn't currently attached to a toplevel"); - bounds *= _attachedTo.Window.Scaling; + bounds *= _attachedTo.Window.RenderScaling; var pixelRect = new PixelRect((int)bounds.X, (int)bounds.Y, Math.Max(1, (int)bounds.Width), Math.Max(1, (int)bounds.Height)); diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 1f1f31db0a..c24abcd230 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -163,7 +163,7 @@ namespace Avalonia.X11 var surfaces = new List { new X11FramebufferSurface(_x11.DeferredDisplay, _renderHandle, - depth, () => Scaling) + depth, () => RenderScaling) }; if (egl != null) @@ -217,7 +217,7 @@ namespace Avalonia.X11 } } - public double Scaling => _window.Scaling; + public double Scaling => _window.RenderScaling; } void UpdateMotifHints() @@ -284,9 +284,9 @@ namespace Avalonia.X11 XSetWMNormalHints(_x11.Display, _handle, ref hints); } - public Size ClientSize => new Size(_realSize.Width / Scaling, _realSize.Height / Scaling); + public Size ClientSize => new Size(_realSize.Width / RenderScaling, _realSize.Height / RenderScaling); - public double Scaling + public double RenderScaling { get { @@ -296,6 +296,8 @@ namespace Avalonia.X11 } private set => _scaling = value; } + + public double DesktopScaling => RenderScaling; public IEnumerable Surfaces { get; } public Action Input { get; set; } @@ -538,14 +540,14 @@ namespace Avalonia.X11 { var monitor = _platform.X11Screens.Screens.OrderBy(x => x.PixelDensity) .FirstOrDefault(m => m.Bounds.Contains(Position)); - newScaling = monitor?.PixelDensity ?? Scaling; + newScaling = monitor?.PixelDensity ?? RenderScaling; } - if (Scaling != newScaling) + if (RenderScaling != newScaling) { var oldScaledSize = ClientSize; - Scaling = newScaling; - ScalingChanged?.Invoke(Scaling); + RenderScaling = newScaling; + ScalingChanged?.Invoke(RenderScaling); SetMinMaxSize(_scaledMinMaxSize.minSize, _scaledMinMaxSize.maxSize); if(!skipResize) Resize(oldScaledSize, true); @@ -707,9 +709,9 @@ namespace Avalonia.X11 private void ScheduleInput(RawInputEventArgs args) { if (args is RawPointerEventArgs mouse) - mouse.Position = mouse.Position / Scaling; + mouse.Position = mouse.Position / RenderScaling; if (args is RawDragEvent drag) - drag.Location = drag.Location / Scaling; + drag.Location = drag.Location / RenderScaling; _lastEvent = new InputEventContainer() {Event = args}; _inputQueue.Enqueue(_lastEvent); @@ -816,11 +818,11 @@ namespace Avalonia.X11 public void Hide() => XUnmapWindow(_x11.Display, _handle); - public Point PointToClient(PixelPoint point) => new Point((point.X - Position.X) / Scaling, (point.Y - Position.Y) / Scaling); + public Point PointToClient(PixelPoint point) => new Point((point.X - Position.X) / RenderScaling, (point.Y - Position.Y) / RenderScaling); public PixelPoint PointToScreen(Point point) => new PixelPoint( - (int)(point.X * Scaling + Position.X), - (int)(point.Y * Scaling + Position.Y)); + (int)(point.X * RenderScaling + Position.X), + (int)(point.Y * RenderScaling + Position.Y)); public void SetSystemDecorations(SystemDecorations enabled) { @@ -840,7 +842,7 @@ namespace Avalonia.X11 Resize(size, true); } - PixelSize ToPixelSize(Size size) => new PixelSize((int)(size.Width * Scaling), (int)(size.Height * Scaling)); + PixelSize ToPixelSize(Size size) => new PixelSize((int)(size.Width * RenderScaling), (int)(size.Height * RenderScaling)); void Resize(Size clientSize, bool force) { @@ -1020,13 +1022,13 @@ namespace Avalonia.X11 { _scaledMinMaxSize = (minSize, maxSize); var min = new PixelSize( - (int)(minSize.Width < 1 ? 1 : minSize.Width * Scaling), - (int)(minSize.Height < 1 ? 1 : minSize.Height * Scaling)); + (int)(minSize.Width < 1 ? 1 : minSize.Width * RenderScaling), + (int)(minSize.Height < 1 ? 1 : minSize.Height * RenderScaling)); const int maxDim = MaxWindowDimension; var max = new PixelSize( - (int)(maxSize.Width > maxDim ? maxDim : Math.Max(min.Width, maxSize.Width * Scaling)), - (int)(maxSize.Height > maxDim ? maxDim : Math.Max(min.Height, maxSize.Height * Scaling))); + (int)(maxSize.Width > maxDim ? maxDim : Math.Max(min.Width, maxSize.Width * RenderScaling)), + (int)(maxSize.Height > maxDim ? maxDim : Math.Max(min.Height, maxSize.Height * RenderScaling))); _minMaxSize = (min, max); UpdateSizeHints(null); diff --git a/src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs b/src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs index b8ae2eb4d8..0a101eec7a 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs @@ -65,7 +65,7 @@ namespace Avalonia.LinuxFramebuffer public IMouseDevice MouseDevice => new MouseDevice(); public IPopupImpl CreatePopup() => null; - public double Scaling => _outputBackend.Scaling; + public double RenderScaling => _outputBackend.Scaling; public IEnumerable Surfaces { get; } public Action Input { get; set; } public Action Paint { get; set; } @@ -77,7 +77,7 @@ namespace Avalonia.LinuxFramebuffer public Action Closed { get; set; } public Action LostFocus { get; set; } - public Size ScaledSize => _outputBackend.PixelSize.ToSize(Scaling); + public Size ScaledSize => _outputBackend.PixelSize.ToSize(RenderScaling); public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel) { } diff --git a/src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs b/src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs index f5d83611bb..3467a33d16 100644 --- a/src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs +++ b/src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs @@ -75,7 +75,7 @@ namespace Avalonia.Win32.Interop.Wpf private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled) { if (msg == (int)UnmanagedMethods.WindowsMessage.WM_DPICHANGED) - _ttl.ScalingChanged?.Invoke(_ttl.Scaling); + _ttl.ScalingChanged?.Invoke(_ttl.RenderScaling); return IntPtr.Zero; } @@ -84,7 +84,7 @@ namespace Avalonia.Win32.Interop.Wpf _currentHwndSource?.RemoveHook(_hook); _currentHwndSource = e.NewSource as HwndSource; _currentHwndSource?.AddHook(_hook); - _ttl.ScalingChanged?.Invoke(_ttl.Scaling); + _ttl.ScalingChanged?.Invoke(_ttl.RenderScaling); } public IRenderer CreateRenderer(IRenderRoot root) @@ -102,7 +102,7 @@ namespace Avalonia.Win32.Interop.Wpf Size ITopLevelImpl.ClientSize => _finalSize; IMouseDevice ITopLevelImpl.MouseDevice => _mouse; - double ITopLevelImpl.Scaling => PresentationSource.FromVisual(this)?.CompositionTarget?.TransformToDevice.M11 ?? 1; + double ITopLevelImpl.RenderScaling => PresentationSource.FromVisual(this)?.CompositionTarget?.TransformToDevice.M11 ?? 1; IEnumerable ITopLevelImpl.Surfaces => _surfaces; diff --git a/src/Windows/Avalonia.Win32/PopupImpl.cs b/src/Windows/Avalonia.Win32/PopupImpl.cs index 525e5e0d52..57da1c4d66 100644 --- a/src/Windows/Avalonia.Win32/PopupImpl.cs +++ b/src/Windows/Avalonia.Win32/PopupImpl.cs @@ -57,7 +57,7 @@ namespace Avalonia.Win32 { var info = UnmanagedMethods.MONITORINFO.Create(); UnmanagedMethods.GetMonitorInfo(monitor, ref info); - _maxAutoSize = info.rcWork.ToPixelRect().ToRect(Scaling).Size; + _maxAutoSize = info.rcWork.ToPixelRect().ToRect(RenderScaling).Size; } } diff --git a/src/Windows/Avalonia.Win32/Win32NativeControlHost.cs b/src/Windows/Avalonia.Win32/Win32NativeControlHost.cs index d7bb2c037e..8f62163d81 100644 --- a/src/Windows/Avalonia.Win32/Win32NativeControlHost.cs +++ b/src/Windows/Avalonia.Win32/Win32NativeControlHost.cs @@ -176,7 +176,7 @@ namespace Avalonia.Win32 UnmanagedMethods.SetWindowPosFlags.SWP_NOACTIVATE); if (_attachedTo == null || _child == null) return; - size *= _attachedTo.Window.Scaling; + size *= _attachedTo.Window.RenderScaling; UnmanagedMethods.MoveWindow(_child.Handle, 0, 0, Math.Max(1, (int)size.Width), Math.Max(1, (int)size.Height), false); } @@ -186,7 +186,7 @@ namespace Avalonia.Win32 CheckDisposed(); if (_attachedTo == null) throw new InvalidOperationException("The control isn't currently attached to a toplevel"); - bounds *= _attachedTo.Window.Scaling; + bounds *= _attachedTo.Window.RenderScaling; var pixelRect = new PixelRect((int)bounds.X, (int)bounds.Y, Math.Max(1, (int)bounds.Width), Math.Max(1, (int)bounds.Height)); diff --git a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs index 0ba1d311bc..ee6845e2eb 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs @@ -343,7 +343,7 @@ namespace Avalonia.Win32 { if (BeginPaint(_hwnd, out PAINTSTRUCT ps) != IntPtr.Zero) { - var f = Scaling; + var f = RenderScaling; var r = ps.rcPaint; Paint?.Invoke(new Rect(r.left / f, r.top / f, (r.right - r.left) / f, (r.bottom - r.top) / f)); @@ -368,7 +368,7 @@ namespace Avalonia.Win32 size == SizeCommand.Maximized)) { var clientSize = new Size(ToInt32(lParam) & 0xffff, ToInt32(lParam) >> 16); - Resized(clientSize / Scaling); + Resized(clientSize / RenderScaling); } var windowState = size == SizeCommand.Maximized ? @@ -406,25 +406,25 @@ namespace Avalonia.Win32 if (_minSize.Width > 0) { mmi.ptMinTrackSize.X = - (int)((_minSize.Width * Scaling) + BorderThickness.Left + BorderThickness.Right); + (int)((_minSize.Width * RenderScaling) + BorderThickness.Left + BorderThickness.Right); } if (_minSize.Height > 0) { mmi.ptMinTrackSize.Y = - (int)((_minSize.Height * Scaling) + BorderThickness.Top + BorderThickness.Bottom); + (int)((_minSize.Height * RenderScaling) + BorderThickness.Top + BorderThickness.Bottom); } if (!double.IsInfinity(_maxSize.Width) && _maxSize.Width > 0) { mmi.ptMaxTrackSize.X = - (int)((_maxSize.Width * Scaling) + BorderThickness.Left + BorderThickness.Right); + (int)((_maxSize.Width * RenderScaling) + BorderThickness.Left + BorderThickness.Right); } if (!double.IsInfinity(_maxSize.Height) && _maxSize.Height > 0) { mmi.ptMaxTrackSize.Y = - (int)((_maxSize.Height * Scaling) + BorderThickness.Top + BorderThickness.Bottom); + (int)((_maxSize.Height * RenderScaling) + BorderThickness.Top + BorderThickness.Bottom); } Marshal.StructureToPtr(mmi, lParam, true); @@ -480,7 +480,7 @@ namespace Avalonia.Win32 private Point DipFromLParam(IntPtr lParam) { - return new Point((short)(ToInt32(lParam) & 0xffff), (short)(ToInt32(lParam) >> 16)) / Scaling; + return new Point((short)(ToInt32(lParam) & 0xffff), (short)(ToInt32(lParam) >> 16)) / RenderScaling; } private PixelPoint PointFromLParam(IntPtr lParam) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs index 2badf99f7f..a3b7574369 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs @@ -37,7 +37,7 @@ namespace Avalonia.Win32 if (_extendTitleBarHint >= 0) { - border_thickness.top = (int)(_extendedMargins.Top * Scaling); + border_thickness.top = (int)(_extendedMargins.Top * RenderScaling); } // Determine if the hit test is for resizing. Default middle (1,1). diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 0ee1342d27..6f22f94056 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -164,7 +164,9 @@ namespace Avalonia.Win32 } } - public double Scaling => _scaling; + public double RenderScaling => _scaling; + + public double DesktopScaling => RenderScaling; public Size ClientSize { @@ -172,7 +174,7 @@ namespace Avalonia.Win32 { GetClientRect(_hwnd, out var rect); - return new Size(rect.right, rect.bottom) / Scaling; + return new Size(rect.right, rect.bottom) / RenderScaling; } } @@ -180,7 +182,7 @@ namespace Avalonia.Win32 public IPlatformHandle Handle { get; private set; } - public virtual Size MaxAutoSizeHint => new Size(_maxTrackSize.X / Scaling, _maxTrackSize.Y / Scaling); + public virtual Size MaxAutoSizeHint => new Size(_maxTrackSize.X / RenderScaling, _maxTrackSize.Y / RenderScaling); public IMouseDevice MouseDevice => _mouseDevice; @@ -342,8 +344,8 @@ namespace Avalonia.Win32 public void Resize(Size value) { - int requestedClientWidth = (int)(value.Width * Scaling); - int requestedClientHeight = (int)(value.Height * Scaling); + int requestedClientWidth = (int)(value.Width * RenderScaling); + int requestedClientHeight = (int)(value.Height * RenderScaling); GetClientRect(_hwnd, out var clientRect); @@ -395,7 +397,7 @@ namespace Avalonia.Win32 public void Invalidate(Rect rect) { - var scaling = Scaling; + var scaling = RenderScaling; var r = new RECT { left = (int)Math.Floor(rect.X * scaling), @@ -411,12 +413,12 @@ namespace Avalonia.Win32 { var p = new POINT { X = point.X, Y = point.Y }; UnmanagedMethods.ScreenToClient(_hwnd, ref p); - return new Point(p.X, p.Y) / Scaling; + return new Point(p.X, p.Y) / RenderScaling; } public PixelPoint PointToScreen(Point point) { - point *= Scaling; + point *= RenderScaling; var p = new POINT { X = (int)point.X, Y = (int)point.Y }; ClientToScreen(_hwnd, ref p); return new PixelPoint(p.X, p.Y); @@ -710,19 +712,19 @@ namespace Avalonia.Win32 if (_extendTitleBarHint != -1) { - borderCaptionThickness.top = (int)(_extendTitleBarHint * Scaling); + borderCaptionThickness.top = (int)(_extendTitleBarHint * RenderScaling); } margins.cyTopHeight = _extendChromeHints.HasFlag(ExtendClientAreaChromeHints.SystemChrome) && !_extendChromeHints.HasFlag(ExtendClientAreaChromeHints.PreferSystemChrome) ? borderCaptionThickness.top : 1; if (WindowState == WindowState.Maximized) { - _extendedMargins = new Thickness(0, (borderCaptionThickness.top - borderThickness.top) / Scaling, 0, 0); - _offScreenMargin = new Thickness(borderThickness.left / Scaling, borderThickness.top / Scaling, borderThickness.right / Scaling, borderThickness.bottom / Scaling); + _extendedMargins = new Thickness(0, (borderCaptionThickness.top - borderThickness.top) / RenderScaling, 0, 0); + _offScreenMargin = new Thickness(borderThickness.left / RenderScaling, borderThickness.top / RenderScaling, borderThickness.right / RenderScaling, borderThickness.bottom / RenderScaling); } else { - _extendedMargins = new Thickness(0, (borderCaptionThickness.top) / Scaling, 0, 0); + _extendedMargins = new Thickness(0, (borderCaptionThickness.top) / RenderScaling, 0, 0); _offScreenMargin = new Thickness(); } @@ -1034,6 +1036,8 @@ namespace Avalonia.Win32 } } + double EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo.Scaling => RenderScaling; + IntPtr EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo.Handle => Handle.Handle; public void SetExtendClientAreaToDecorationsHint(bool hint) diff --git a/src/iOS/Avalonia.iOS/TopLevelImpl.cs b/src/iOS/Avalonia.iOS/TopLevelImpl.cs index 83a68990d7..5a85a5ea88 100644 --- a/src/iOS/Avalonia.iOS/TopLevelImpl.cs +++ b/src/iOS/Avalonia.iOS/TopLevelImpl.cs @@ -48,7 +48,7 @@ namespace Avalonia.iOS public new IPlatformHandle Handle => null; - public double Scaling => UIScreen.MainScreen.Scale; + public double RenderScaling => UIScreen.MainScreen.Scale; public override void LayoutSubviews() => Resized?.Invoke(ClientSize); diff --git a/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs b/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs index cf8f7c266a..7a2109e5a7 100644 --- a/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs @@ -296,7 +296,7 @@ namespace Avalonia.Controls.UnitTests var windowImpl = MockWindowingPlatform.CreateWindowMock(); popupImpl = MockWindowingPlatform.CreatePopupMock(windowImpl.Object); - popupImpl.SetupGet(x => x.Scaling).Returns(1); + popupImpl.SetupGet(x => x.RenderScaling).Returns(1); windowImpl.Setup(x => x.CreatePopup()).Returns(popupImpl.Object); windowImpl.Setup(x => x.Screen).Returns(screenImpl.Object); diff --git a/tests/Avalonia.Controls.UnitTests/DesktopStyleApplicationLifetimeTests.cs b/tests/Avalonia.Controls.UnitTests/DesktopStyleApplicationLifetimeTests.cs index dee7a84812..e6deabfe25 100644 --- a/tests/Avalonia.Controls.UnitTests/DesktopStyleApplicationLifetimeTests.cs +++ b/tests/Avalonia.Controls.UnitTests/DesktopStyleApplicationLifetimeTests.cs @@ -191,7 +191,7 @@ namespace Avalonia.Controls.UnitTests { var windowImpl = new Mock(); windowImpl.SetupProperty(x => x.Closed); - windowImpl.Setup(x => x.Scaling).Returns(1); + windowImpl.Setup(x => x.RenderScaling).Returns(1); var services = TestServices.StyledWindow.With( windowingPlatform: new MockWindowingPlatform(() => windowImpl.Object)); diff --git a/tests/Avalonia.Controls.UnitTests/TopLevelTests.cs b/tests/Avalonia.Controls.UnitTests/TopLevelTests.cs index e49e273bec..6b30aed257 100644 --- a/tests/Avalonia.Controls.UnitTests/TopLevelTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TopLevelTests.cs @@ -93,7 +93,7 @@ namespace Avalonia.Controls.UnitTests { var impl = new Mock(); impl.SetupProperty(x => x.Resized); - impl.SetupGet(x => x.Scaling).Returns(1); + impl.SetupGet(x => x.RenderScaling).Returns(1); var target = new TestTopLevel(impl.Object) { @@ -290,7 +290,7 @@ namespace Avalonia.Controls.UnitTests using (UnitTestApplication.Start(TestServices.StyledWindow)) { var impl = new Mock(); - impl.SetupGet(x => x.Scaling).Returns(1); + impl.SetupGet(x => x.RenderScaling).Returns(1); var child = new Border { Classes = { "foo" } }; var target = new TestTopLevel(impl.Object) diff --git a/tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs b/tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs index 697ea9cff8..7e3130377f 100644 --- a/tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs +++ b/tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs @@ -110,7 +110,7 @@ namespace Avalonia.Controls.UnitTests public void IsVisible_Should_Be_False_Atfer_Impl_Signals_Close() { var windowImpl = new Mock(); - windowImpl.Setup(x => x.Scaling).Returns(1); + windowImpl.Setup(x => x.RenderScaling).Returns(1); windowImpl.SetupProperty(x => x.Closed); using (UnitTestApplication.Start(TestServices.StyledWindow)) @@ -128,7 +128,7 @@ namespace Avalonia.Controls.UnitTests public void Setting_IsVisible_True_Shows_Window() { var windowImpl = new Mock(); - windowImpl.Setup(x => x.Scaling).Returns(1); + windowImpl.Setup(x => x.RenderScaling).Returns(1); using (UnitTestApplication.Start(TestServices.StyledWindow)) { @@ -143,7 +143,7 @@ namespace Avalonia.Controls.UnitTests public void Setting_IsVisible_False_Hides_Window() { var windowImpl = new Mock(); - windowImpl.Setup(x => x.Scaling).Returns(1); + windowImpl.Setup(x => x.RenderScaling).Returns(1); using (UnitTestApplication.Start(TestServices.StyledWindow)) { @@ -208,7 +208,7 @@ namespace Avalonia.Controls.UnitTests { var renderer = new Mock(); var windowImpl = new Mock(); - windowImpl.Setup(x => x.Scaling).Returns(1); + windowImpl.Setup(x => x.RenderScaling).Returns(1); windowImpl.SetupProperty(x => x.Closed); windowImpl.Setup(x => x.CreateRenderer(It.IsAny())).Returns(renderer.Object); @@ -237,7 +237,7 @@ namespace Avalonia.Controls.UnitTests public TestWindowBase(IRenderer renderer = null) : base(Mock.Of(x => - x.Scaling == 1 && + x.RenderScaling == 1 && x.CreateRenderer(It.IsAny()) == renderer)) { } diff --git a/tests/Avalonia.Controls.UnitTests/WindowTests.cs b/tests/Avalonia.Controls.UnitTests/WindowTests.cs index e2b0def00b..2b736ae38b 100644 --- a/tests/Avalonia.Controls.UnitTests/WindowTests.cs +++ b/tests/Avalonia.Controls.UnitTests/WindowTests.cs @@ -100,7 +100,7 @@ namespace Avalonia.Controls.UnitTests { var windowImpl = new Mock(); windowImpl.SetupProperty(x => x.Closed); - windowImpl.Setup(x => x.Scaling).Returns(1); + windowImpl.Setup(x => x.RenderScaling).Returns(1); var services = TestServices.StyledWindow.With( windowingPlatform: new MockWindowingPlatform(() => windowImpl.Object)); @@ -206,7 +206,7 @@ namespace Avalonia.Controls.UnitTests var parent = new Mock(); var windowImpl = new Mock(); windowImpl.SetupProperty(x => x.Closed); - windowImpl.Setup(x => x.Scaling).Returns(1); + windowImpl.Setup(x => x.RenderScaling).Returns(1); var target = new Window(windowImpl.Object); var task = target.ShowDialog(parent.Object); @@ -245,7 +245,7 @@ namespace Avalonia.Controls.UnitTests var parent = new Mock(); var windowImpl = new Mock(); windowImpl.SetupProperty(x => x.Closed); - windowImpl.Setup(x => x.Scaling).Returns(1); + windowImpl.Setup(x => x.RenderScaling).Returns(1); var target = new Window(windowImpl.Object); var task = target.ShowDialog(parent.Object); @@ -273,7 +273,7 @@ namespace Avalonia.Controls.UnitTests var windowImpl = MockWindowingPlatform.CreateWindowMock(); windowImpl.Setup(x => x.ClientSize).Returns(new Size(800, 480)); - windowImpl.Setup(x => x.Scaling).Returns(1); + windowImpl.Setup(x => x.RenderScaling).Returns(1); windowImpl.Setup(x => x.Screen).Returns(screens.Object); using (UnitTestApplication.Start(TestServices.StyledWindow)) @@ -298,12 +298,12 @@ namespace Avalonia.Controls.UnitTests var parentWindowImpl = MockWindowingPlatform.CreateWindowMock(); parentWindowImpl.Setup(x => x.ClientSize).Returns(new Size(800, 480)); parentWindowImpl.Setup(x => x.MaxAutoSizeHint).Returns(new Size(1920, 1080)); - parentWindowImpl.Setup(x => x.Scaling).Returns(1); + parentWindowImpl.Setup(x => x.RenderScaling).Returns(1); var windowImpl = MockWindowingPlatform.CreateWindowMock(); windowImpl.Setup(x => x.ClientSize).Returns(new Size(320, 200)); windowImpl.Setup(x => x.MaxAutoSizeHint).Returns(new Size(1920, 1080)); - windowImpl.Setup(x => x.Scaling).Returns(1); + windowImpl.Setup(x => x.RenderScaling).Returns(1); var parentWindowServices = TestServices.StyledWindow.With( windowingPlatform: new MockWindowingPlatform(() => parentWindowImpl.Object)); @@ -565,7 +565,7 @@ namespace Avalonia.Controls.UnitTests private IWindowImpl CreateImpl(Mock renderer) { return Mock.Of(x => - x.Scaling == 1 && + x.RenderScaling == 1 && x.CreateRenderer(It.IsAny()) == renderer.Object); } diff --git a/tests/Avalonia.Controls.UnitTests/WindowingPlatformMock.cs b/tests/Avalonia.Controls.UnitTests/WindowingPlatformMock.cs index 25e8c82b1a..bf1322afbc 100644 --- a/tests/Avalonia.Controls.UnitTests/WindowingPlatformMock.cs +++ b/tests/Avalonia.Controls.UnitTests/WindowingPlatformMock.cs @@ -17,7 +17,7 @@ namespace Avalonia.Controls.UnitTests public IWindowImpl CreateWindow() { - return _windowImpl?.Invoke() ?? Mock.Of(x => x.Scaling == 1); + return _windowImpl?.Invoke() ?? Mock.Of(x => x.RenderScaling == 1); } public IWindowImpl CreateEmbeddableWindow() @@ -25,6 +25,6 @@ namespace Avalonia.Controls.UnitTests throw new NotImplementedException(); } - public IPopupImpl CreatePopup() => _popupImpl?.Invoke() ?? Mock.Of(x => x.Scaling == 1); + public IPopupImpl CreatePopup() => _popupImpl?.Invoke() ?? Mock.Of(x => x.RenderScaling == 1); } } diff --git a/tests/Avalonia.LeakTests/ControlTests.cs b/tests/Avalonia.LeakTests/ControlTests.cs index 00ef503b8d..530b8fa20c 100644 --- a/tests/Avalonia.LeakTests/ControlTests.cs +++ b/tests/Avalonia.LeakTests/ControlTests.cs @@ -355,7 +355,7 @@ namespace Avalonia.LeakTests var renderer = new Mock(); renderer.Setup(x => x.Dispose()); var impl = new Mock(); - impl.SetupGet(x => x.Scaling).Returns(1); + impl.SetupGet(x => x.RenderScaling).Returns(1); impl.SetupProperty(x => x.Closed); impl.Setup(x => x.CreateRenderer(It.IsAny())).Returns(renderer.Object); impl.Setup(x => x.Dispose()).Callback(() => impl.Object.Closed()); diff --git a/tests/Avalonia.UnitTests/MockWindowingPlatform.cs b/tests/Avalonia.UnitTests/MockWindowingPlatform.cs index 48a333dc54..e5fcce13c0 100644 --- a/tests/Avalonia.UnitTests/MockWindowingPlatform.cs +++ b/tests/Avalonia.UnitTests/MockWindowingPlatform.cs @@ -29,7 +29,7 @@ namespace Avalonia.UnitTests windowImpl.SetupAllProperties(); windowImpl.Setup(x => x.ClientSize).Returns(() => clientSize); windowImpl.Setup(x => x.MaxAutoSizeHint).Returns(s_screenSize); - windowImpl.Setup(x => x.Scaling).Returns(1); + windowImpl.Setup(x => x.RenderScaling).Returns(1); windowImpl.Setup(x => x.Screen).Returns(CreateScreenMock().Object); windowImpl.Setup(x => x.Position).Returns(() => position); SetupToplevel(windowImpl); @@ -81,7 +81,7 @@ namespace Avalonia.UnitTests popupImpl.SetupAllProperties(); popupImpl.Setup(x => x.ClientSize).Returns(() => clientSize); popupImpl.Setup(x => x.MaxAutoSizeHint).Returns(s_screenSize); - popupImpl.Setup(x => x.Scaling).Returns(1); + popupImpl.Setup(x => x.RenderScaling).Returns(1); popupImpl.Setup(x => x.PopupPositioner).Returns(positioner); SetupToplevel(popupImpl); From 2ad40026865fd2189fbabfaa20df1bdbd56f06ce Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Mon, 20 Jul 2020 16:56:00 -0300 Subject: [PATCH 035/344] fix unit tests. --- .../DesktopStyleApplicationLifetimeTests.cs | 2 +- tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs | 8 ++++---- tests/Avalonia.Controls.UnitTests/WindowTests.cs | 12 ++++++------ tests/Avalonia.UnitTests/MockWindowingPlatform.cs | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/Avalonia.Controls.UnitTests/DesktopStyleApplicationLifetimeTests.cs b/tests/Avalonia.Controls.UnitTests/DesktopStyleApplicationLifetimeTests.cs index e6deabfe25..837a62f40e 100644 --- a/tests/Avalonia.Controls.UnitTests/DesktopStyleApplicationLifetimeTests.cs +++ b/tests/Avalonia.Controls.UnitTests/DesktopStyleApplicationLifetimeTests.cs @@ -191,7 +191,7 @@ namespace Avalonia.Controls.UnitTests { var windowImpl = new Mock(); windowImpl.SetupProperty(x => x.Closed); - windowImpl.Setup(x => x.RenderScaling).Returns(1); + windowImpl.Setup(x => x.DesktopScaling).Returns(1); var services = TestServices.StyledWindow.With( windowingPlatform: new MockWindowingPlatform(() => windowImpl.Object)); diff --git a/tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs b/tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs index 7e3130377f..1c72eb5069 100644 --- a/tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs +++ b/tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs @@ -110,7 +110,7 @@ namespace Avalonia.Controls.UnitTests public void IsVisible_Should_Be_False_Atfer_Impl_Signals_Close() { var windowImpl = new Mock(); - windowImpl.Setup(x => x.RenderScaling).Returns(1); + windowImpl.Setup(x => x.DesktopScaling).Returns(1); windowImpl.SetupProperty(x => x.Closed); using (UnitTestApplication.Start(TestServices.StyledWindow)) @@ -128,7 +128,7 @@ namespace Avalonia.Controls.UnitTests public void Setting_IsVisible_True_Shows_Window() { var windowImpl = new Mock(); - windowImpl.Setup(x => x.RenderScaling).Returns(1); + windowImpl.Setup(x => x.DesktopScaling).Returns(1); using (UnitTestApplication.Start(TestServices.StyledWindow)) { @@ -143,7 +143,7 @@ namespace Avalonia.Controls.UnitTests public void Setting_IsVisible_False_Hides_Window() { var windowImpl = new Mock(); - windowImpl.Setup(x => x.RenderScaling).Returns(1); + windowImpl.Setup(x => x.DesktopScaling).Returns(1); using (UnitTestApplication.Start(TestServices.StyledWindow)) { @@ -208,7 +208,7 @@ namespace Avalonia.Controls.UnitTests { var renderer = new Mock(); var windowImpl = new Mock(); - windowImpl.Setup(x => x.RenderScaling).Returns(1); + windowImpl.Setup(x => x.DesktopScaling).Returns(1); windowImpl.SetupProperty(x => x.Closed); windowImpl.Setup(x => x.CreateRenderer(It.IsAny())).Returns(renderer.Object); diff --git a/tests/Avalonia.Controls.UnitTests/WindowTests.cs b/tests/Avalonia.Controls.UnitTests/WindowTests.cs index 2b736ae38b..5cf65115bb 100644 --- a/tests/Avalonia.Controls.UnitTests/WindowTests.cs +++ b/tests/Avalonia.Controls.UnitTests/WindowTests.cs @@ -100,7 +100,7 @@ namespace Avalonia.Controls.UnitTests { var windowImpl = new Mock(); windowImpl.SetupProperty(x => x.Closed); - windowImpl.Setup(x => x.RenderScaling).Returns(1); + windowImpl.Setup(x => x.DesktopScaling).Returns(1); var services = TestServices.StyledWindow.With( windowingPlatform: new MockWindowingPlatform(() => windowImpl.Object)); @@ -206,7 +206,7 @@ namespace Avalonia.Controls.UnitTests var parent = new Mock(); var windowImpl = new Mock(); windowImpl.SetupProperty(x => x.Closed); - windowImpl.Setup(x => x.RenderScaling).Returns(1); + windowImpl.Setup(x => x.DesktopScaling).Returns(1); var target = new Window(windowImpl.Object); var task = target.ShowDialog(parent.Object); @@ -245,7 +245,7 @@ namespace Avalonia.Controls.UnitTests var parent = new Mock(); var windowImpl = new Mock(); windowImpl.SetupProperty(x => x.Closed); - windowImpl.Setup(x => x.RenderScaling).Returns(1); + windowImpl.Setup(x => x.DesktopScaling).Returns(1); var target = new Window(windowImpl.Object); var task = target.ShowDialog(parent.Object); @@ -273,7 +273,7 @@ namespace Avalonia.Controls.UnitTests var windowImpl = MockWindowingPlatform.CreateWindowMock(); windowImpl.Setup(x => x.ClientSize).Returns(new Size(800, 480)); - windowImpl.Setup(x => x.RenderScaling).Returns(1); + windowImpl.Setup(x => x.DesktopScaling).Returns(1); windowImpl.Setup(x => x.Screen).Returns(screens.Object); using (UnitTestApplication.Start(TestServices.StyledWindow)) @@ -298,12 +298,12 @@ namespace Avalonia.Controls.UnitTests var parentWindowImpl = MockWindowingPlatform.CreateWindowMock(); parentWindowImpl.Setup(x => x.ClientSize).Returns(new Size(800, 480)); parentWindowImpl.Setup(x => x.MaxAutoSizeHint).Returns(new Size(1920, 1080)); - parentWindowImpl.Setup(x => x.RenderScaling).Returns(1); + parentWindowImpl.Setup(x => x.DesktopScaling).Returns(1); var windowImpl = MockWindowingPlatform.CreateWindowMock(); windowImpl.Setup(x => x.ClientSize).Returns(new Size(320, 200)); windowImpl.Setup(x => x.MaxAutoSizeHint).Returns(new Size(1920, 1080)); - windowImpl.Setup(x => x.RenderScaling).Returns(1); + windowImpl.Setup(x => x.DesktopScaling).Returns(1); var parentWindowServices = TestServices.StyledWindow.With( windowingPlatform: new MockWindowingPlatform(() => parentWindowImpl.Object)); diff --git a/tests/Avalonia.UnitTests/MockWindowingPlatform.cs b/tests/Avalonia.UnitTests/MockWindowingPlatform.cs index e5fcce13c0..e265b49af3 100644 --- a/tests/Avalonia.UnitTests/MockWindowingPlatform.cs +++ b/tests/Avalonia.UnitTests/MockWindowingPlatform.cs @@ -29,7 +29,7 @@ namespace Avalonia.UnitTests windowImpl.SetupAllProperties(); windowImpl.Setup(x => x.ClientSize).Returns(() => clientSize); windowImpl.Setup(x => x.MaxAutoSizeHint).Returns(s_screenSize); - windowImpl.Setup(x => x.RenderScaling).Returns(1); + windowImpl.Setup(x => x.DesktopScaling).Returns(1); windowImpl.Setup(x => x.Screen).Returns(CreateScreenMock().Object); windowImpl.Setup(x => x.Position).Returns(() => position); SetupToplevel(windowImpl); From 87c326a8fd0c7e54c60750179b00231e8cef9168 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Mon, 20 Jul 2020 17:13:27 -0300 Subject: [PATCH 036/344] fix mocks. --- .../DesktopStyleApplicationLifetimeTests.cs | 1 + tests/Avalonia.UnitTests/MockWindowingPlatform.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/Avalonia.Controls.UnitTests/DesktopStyleApplicationLifetimeTests.cs b/tests/Avalonia.Controls.UnitTests/DesktopStyleApplicationLifetimeTests.cs index 837a62f40e..84f02aeda5 100644 --- a/tests/Avalonia.Controls.UnitTests/DesktopStyleApplicationLifetimeTests.cs +++ b/tests/Avalonia.Controls.UnitTests/DesktopStyleApplicationLifetimeTests.cs @@ -192,6 +192,7 @@ namespace Avalonia.Controls.UnitTests var windowImpl = new Mock(); windowImpl.SetupProperty(x => x.Closed); windowImpl.Setup(x => x.DesktopScaling).Returns(1); + windowImpl.Setup(x => x.RenderScaling).Returns(1); var services = TestServices.StyledWindow.With( windowingPlatform: new MockWindowingPlatform(() => windowImpl.Object)); diff --git a/tests/Avalonia.UnitTests/MockWindowingPlatform.cs b/tests/Avalonia.UnitTests/MockWindowingPlatform.cs index e265b49af3..67503ef0d0 100644 --- a/tests/Avalonia.UnitTests/MockWindowingPlatform.cs +++ b/tests/Avalonia.UnitTests/MockWindowingPlatform.cs @@ -30,6 +30,7 @@ namespace Avalonia.UnitTests windowImpl.Setup(x => x.ClientSize).Returns(() => clientSize); windowImpl.Setup(x => x.MaxAutoSizeHint).Returns(s_screenSize); windowImpl.Setup(x => x.DesktopScaling).Returns(1); + windowImpl.Setup(x => x.RenderScaling).Returns(1); windowImpl.Setup(x => x.Screen).Returns(CreateScreenMock().Object); windowImpl.Setup(x => x.Position).Returns(() => position); SetupToplevel(windowImpl); From 4aa51e80da8fda5314b0913d42dc3495dced8b1d Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Mon, 20 Jul 2020 17:26:03 -0300 Subject: [PATCH 037/344] fix more tests. --- tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs | 4 ++++ tests/Avalonia.Controls.UnitTests/WindowTests.cs | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs b/tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs index 1c72eb5069..84f212d1b3 100644 --- a/tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs +++ b/tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs @@ -111,6 +111,7 @@ namespace Avalonia.Controls.UnitTests { var windowImpl = new Mock(); windowImpl.Setup(x => x.DesktopScaling).Returns(1); + windowImpl.Setup(x => x.RenderScaling).Returns(1); windowImpl.SetupProperty(x => x.Closed); using (UnitTestApplication.Start(TestServices.StyledWindow)) @@ -129,6 +130,7 @@ namespace Avalonia.Controls.UnitTests { var windowImpl = new Mock(); windowImpl.Setup(x => x.DesktopScaling).Returns(1); + windowImpl.Setup(x => x.RenderScaling).Returns(1); using (UnitTestApplication.Start(TestServices.StyledWindow)) { @@ -144,6 +146,7 @@ namespace Avalonia.Controls.UnitTests { var windowImpl = new Mock(); windowImpl.Setup(x => x.DesktopScaling).Returns(1); + windowImpl.Setup(x => x.RenderScaling).Returns(1); using (UnitTestApplication.Start(TestServices.StyledWindow)) { @@ -209,6 +212,7 @@ namespace Avalonia.Controls.UnitTests var renderer = new Mock(); var windowImpl = new Mock(); windowImpl.Setup(x => x.DesktopScaling).Returns(1); + windowImpl.Setup(x => x.RenderScaling).Returns(1); windowImpl.SetupProperty(x => x.Closed); windowImpl.Setup(x => x.CreateRenderer(It.IsAny())).Returns(renderer.Object); diff --git a/tests/Avalonia.Controls.UnitTests/WindowTests.cs b/tests/Avalonia.Controls.UnitTests/WindowTests.cs index 5cf65115bb..ba29001cf3 100644 --- a/tests/Avalonia.Controls.UnitTests/WindowTests.cs +++ b/tests/Avalonia.Controls.UnitTests/WindowTests.cs @@ -101,6 +101,7 @@ namespace Avalonia.Controls.UnitTests var windowImpl = new Mock(); windowImpl.SetupProperty(x => x.Closed); windowImpl.Setup(x => x.DesktopScaling).Returns(1); + windowImpl.Setup(x => x.RenderScaling).Returns(1); var services = TestServices.StyledWindow.With( windowingPlatform: new MockWindowingPlatform(() => windowImpl.Object)); @@ -207,6 +208,7 @@ namespace Avalonia.Controls.UnitTests var windowImpl = new Mock(); windowImpl.SetupProperty(x => x.Closed); windowImpl.Setup(x => x.DesktopScaling).Returns(1); + windowImpl.Setup(x => x.RenderScaling).Returns(1); var target = new Window(windowImpl.Object); var task = target.ShowDialog(parent.Object); @@ -246,6 +248,7 @@ namespace Avalonia.Controls.UnitTests var windowImpl = new Mock(); windowImpl.SetupProperty(x => x.Closed); windowImpl.Setup(x => x.DesktopScaling).Returns(1); + windowImpl.Setup(x => x.RenderScaling).Returns(1); var target = new Window(windowImpl.Object); var task = target.ShowDialog(parent.Object); @@ -274,6 +277,7 @@ namespace Avalonia.Controls.UnitTests var windowImpl = MockWindowingPlatform.CreateWindowMock(); windowImpl.Setup(x => x.ClientSize).Returns(new Size(800, 480)); windowImpl.Setup(x => x.DesktopScaling).Returns(1); + windowImpl.Setup(x => x.RenderScaling).Returns(1); windowImpl.Setup(x => x.Screen).Returns(screens.Object); using (UnitTestApplication.Start(TestServices.StyledWindow)) @@ -299,11 +303,13 @@ namespace Avalonia.Controls.UnitTests parentWindowImpl.Setup(x => x.ClientSize).Returns(new Size(800, 480)); parentWindowImpl.Setup(x => x.MaxAutoSizeHint).Returns(new Size(1920, 1080)); parentWindowImpl.Setup(x => x.DesktopScaling).Returns(1); + parentWindowImpl.Setup(x => x.RenderScaling).Returns(1); var windowImpl = MockWindowingPlatform.CreateWindowMock(); windowImpl.Setup(x => x.ClientSize).Returns(new Size(320, 200)); windowImpl.Setup(x => x.MaxAutoSizeHint).Returns(new Size(1920, 1080)); windowImpl.Setup(x => x.DesktopScaling).Returns(1); + windowImpl.Setup(x => x.RenderScaling).Returns(1); var parentWindowServices = TestServices.StyledWindow.With( windowingPlatform: new MockWindowingPlatform(() => parentWindowImpl.Object)); From 88db585d42ff663fb42ab1d3ef6bda5485298d68 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Mon, 20 Jul 2020 17:52:56 -0300 Subject: [PATCH 038/344] fix calculation of working area. --- native/Avalonia.Native/src/OSX/Screens.mm | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/native/Avalonia.Native/src/OSX/Screens.mm b/native/Avalonia.Native/src/OSX/Screens.mm index 278daf9a18..455cfa2e41 100644 --- a/native/Avalonia.Native/src/OSX/Screens.mm +++ b/native/Avalonia.Native/src/OSX/Screens.mm @@ -4,6 +4,14 @@ class Screens : public ComSingleObject { public: FORWARD_IUNKNOWN() + + private: + CGFloat PrimaryDisplayHeight() + { + return NSMaxY([[[NSScreen screens] firstObject] frame]); + } + +public: virtual HRESULT GetScreenCount (int* ret) override { @autoreleasepool @@ -25,15 +33,15 @@ class Screens : public ComSingleObject auto screen = [[NSScreen screens] objectAtIndex:index]; - ret->Bounds.X = [screen frame].origin.x; - ret->Bounds.Y = [screen frame].origin.y; ret->Bounds.Height = [screen frame].size.height; ret->Bounds.Width = [screen frame].size.width; + ret->Bounds.X = [screen frame].origin.x; + ret->Bounds.Y = PrimaryDisplayHeight() - [screen frame].origin.y - ret->Bounds.Height; - ret->WorkingArea.X = [screen visibleFrame].origin.x; - ret->WorkingArea.Y = [screen visibleFrame].origin.y; ret->WorkingArea.Height = [screen visibleFrame].size.height; ret->WorkingArea.Width = [screen visibleFrame].size.width; + ret->WorkingArea.X = [screen visibleFrame].origin.x; + ret->WorkingArea.Y = ret->Bounds.Height - [screen visibleFrame].origin.y - ret->WorkingArea.Height; ret->PixelDensity = [screen backingScaleFactor]; From 297ed15bb5ae08ab06cbc22b2de004dd8f786bc4 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Mon, 20 Jul 2020 20:54:33 -0300 Subject: [PATCH 039/344] fix sizetocontent on win32. --- src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs index ee6845e2eb..25a34561fc 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs @@ -402,6 +402,8 @@ namespace Avalonia.Win32 case WindowsMessage.WM_GETMINMAXINFO: { MINMAXINFO mmi = Marshal.PtrToStructure(lParam); + + _maxTrackSize = mmi.ptMaxTrackSize; if (_minSize.Width > 0) { From b0bcd2e5e62ce4ea94a094677cdb191adf53c214 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Mon, 20 Jul 2020 21:16:35 -0300 Subject: [PATCH 040/344] dont emit excessive Resized events on OSX. --- native/Avalonia.Native/src/OSX/window.mm | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/native/Avalonia.Native/src/OSX/window.mm b/native/Avalonia.Native/src/OSX/window.mm index 872269bb26..2d0ffbe4f0 100644 --- a/native/Avalonia.Native/src/OSX/window.mm +++ b/native/Avalonia.Native/src/OSX/window.mm @@ -1291,10 +1291,15 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent _parent->UpdateCursor(); auto fsize = [self convertSizeToBacking: [self frame].size]; - _lastPixelSize.Width = (int)fsize.width; - _lastPixelSize.Height = (int)fsize.height; - [self updateRenderTarget]; - _parent->BaseEvents->Resized(AvnSize{newSize.width, newSize.height}); + + if(_lastPixelSize.Width != (int)fsize.width || _lastPixelSize.Height != (int)fsize.height) + { + _lastPixelSize.Width = (int)fsize.width; + _lastPixelSize.Height = (int)fsize.height; + [self updateRenderTarget]; + + _parent->BaseEvents->Resized(AvnSize{newSize.width, newSize.height}); + } } - (void)updateLayer From e5324684a179e4ede5cfb5982f948ac18b3cbf93 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Mon, 20 Jul 2020 22:15:12 -0300 Subject: [PATCH 041/344] ensure managed titlebar is attached in window when template is applied. --- src/Avalonia.Controls/Chrome/TitleBar.cs | 8 ++++---- src/Avalonia.Controls/Window.cs | 13 ++++++++++++- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/Avalonia.Controls/Chrome/TitleBar.cs b/src/Avalonia.Controls/Chrome/TitleBar.cs index 78b49d2a03..91cbc8b497 100644 --- a/src/Avalonia.Controls/Chrome/TitleBar.cs +++ b/src/Avalonia.Controls/Chrome/TitleBar.cs @@ -29,12 +29,12 @@ namespace Avalonia.Controls.Chrome { if (_disposables == null) { - var layer = ChromeOverlayLayer.GetOverlayLayer(_hostWindow); - - layer?.Children.Add(this); - if (_hostWindow != null) { + var layer = ChromeOverlayLayer.GetOverlayLayer(_hostWindow); + + layer?.Children.Add(this); + _disposables = new CompositeDisposable { _hostWindow.GetObservable(Window.WindowDecorationMarginProperty) diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 90e5c22c45..874c94a974 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -6,6 +6,7 @@ using System.Reactive.Linq; using System.Threading.Tasks; using Avalonia.Controls.Chrome; using Avalonia.Controls.Platform; +using Avalonia.Controls.Primitives; using Avalonia.Data; using Avalonia.Input; using Avalonia.Interactivity; @@ -75,6 +76,7 @@ namespace Avalonia.Controls private bool _isExtendedIntoWindowDecorations; private Thickness _windowDecorationMargin; private Thickness _offScreenMargin; + private bool _templateApplied; /// /// Defines the property. @@ -553,7 +555,7 @@ namespace Avalonia.Controls WindowDecorationMargin = PlatformImpl.ExtendedMargins; OffScreenMargin = PlatformImpl.OffScreenMargin; - if (PlatformImpl.NeedsManagedDecorations) + if (PlatformImpl.NeedsManagedDecorations && _templateApplied) { if (_managedTitleBar == null) { @@ -568,6 +570,15 @@ namespace Avalonia.Controls } } + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) + { + base.OnApplyTemplate(e); + + _templateApplied = true; + + ExtendClientAreaToDecorationsChanged(PlatformImpl.IsClientAreaExtendedToDecorations); + } + /// /// Hides the window but does not close it. /// From d8604567eec0445e2898a78437b5016b021a2cd4 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Mon, 20 Jul 2020 22:38:31 -0300 Subject: [PATCH 042/344] fix window background interfering with titlebar and window dragging. --- src/Avalonia.Themes.Default/Window.xaml | 31 ++++++++++++------------- src/Avalonia.Themes.Fluent/Window.xaml | 19 +++++++-------- 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/src/Avalonia.Themes.Default/Window.xaml b/src/Avalonia.Themes.Default/Window.xaml index 739887fb35..2aa62df01f 100644 --- a/src/Avalonia.Themes.Default/Window.xaml +++ b/src/Avalonia.Themes.Default/Window.xaml @@ -1,23 +1,22 @@ + + + + + + + + + + diff --git a/samples/ControlCatalog/ViewModels/MenuPageViewModel.cs b/samples/ControlCatalog/ViewModels/MenuPageViewModel.cs index dc9c4a8f49..9e7ae8b716 100644 --- a/samples/ControlCatalog/ViewModels/MenuPageViewModel.cs +++ b/samples/ControlCatalog/ViewModels/MenuPageViewModel.cs @@ -17,6 +17,23 @@ namespace ControlCatalog.ViewModels SaveCommand = ReactiveCommand.Create(Save, Observable.Return(false)); OpenRecentCommand = ReactiveCommand.Create(OpenRecent); + var recentItems = new[] + { + new MenuItemViewModel + { + Header = "File1.txt", + Command = OpenRecentCommand, + CommandParameter = @"c:\foo\File1.txt" + }, + new MenuItemViewModel + { + Header = "File2.txt", + Command = OpenRecentCommand, + CommandParameter = @"c:\foo\File2.txt" + }, + }; + + RecentItems = recentItems; MenuItems = new[] { new MenuItemViewModel @@ -24,27 +41,13 @@ namespace ControlCatalog.ViewModels Header = "_File", Items = new[] { - new MenuItemViewModel { Header = "_Open...", Command = OpenCommand }, + new MenuItemViewModel { Header = "O_pen...", Command = OpenCommand }, new MenuItemViewModel { Header = "Save", Command = SaveCommand }, new MenuItemViewModel { Header = "-" }, new MenuItemViewModel { Header = "Recent", - Items = new[] - { - new MenuItemViewModel - { - Header = "File1.txt", - Command = OpenRecentCommand, - CommandParameter = @"c:\foo\File1.txt" - }, - new MenuItemViewModel - { - Header = "File2.txt", - Command = OpenRecentCommand, - CommandParameter = @"c:\foo\File2.txt" - }, - } + Items = recentItems }, } }, @@ -61,6 +64,7 @@ namespace ControlCatalog.ViewModels } public IReadOnlyList MenuItems { get; set; } + public IReadOnlyList RecentItems { get; set; } public ReactiveCommand OpenCommand { get; } public ReactiveCommand SaveCommand { get; } public ReactiveCommand OpenRecentCommand { get; } From 3c444dc279fe8a030d489315ddc8888b21140a2e Mon Sep 17 00:00:00 2001 From: Maksym Katsydan Date: Tue, 21 Jul 2020 19:49:58 -0400 Subject: [PATCH 054/344] Fix MenuItem:pressed state --- src/Avalonia.Themes.Fluent/MenuItem.xaml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Avalonia.Themes.Fluent/MenuItem.xaml b/src/Avalonia.Themes.Fluent/MenuItem.xaml index fbb994e90c..4899bf264f 100644 --- a/src/Avalonia.Themes.Fluent/MenuItem.xaml +++ b/src/Avalonia.Themes.Fluent/MenuItem.xaml @@ -183,10 +183,10 @@ - + @@ -212,14 +212,15 @@ - - - From 5e2c641f02f0c6d4382ed1a040c86c5576d825ca Mon Sep 17 00:00:00 2001 From: Maksym Katsydan Date: Tue, 21 Jul 2020 20:21:13 -0400 Subject: [PATCH 055/344] Move Popup in Fluent MenuItem to another parent node and add MenuFlyoutSubItemPopupHorizontalOffset --- src/Avalonia.Themes.Fluent/MenuItem.xaml | 155 ++++++++++++----------- 1 file changed, 79 insertions(+), 76 deletions(-) diff --git a/src/Avalonia.Themes.Fluent/MenuItem.xaml b/src/Avalonia.Themes.Fluent/MenuItem.xaml index 4899bf264f..0442c38025 100644 --- a/src/Avalonia.Themes.Fluent/MenuItem.xaml +++ b/src/Avalonia.Themes.Fluent/MenuItem.xaml @@ -40,6 +40,7 @@ + -4 0,4,0,4 0,0,12,0 24,0,0,0 @@ -54,83 +55,85 @@ - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + From bb46dee949714829a7515e0637c1f32b5061c61d Mon Sep 17 00:00:00 2001 From: Maksym Katsydan Date: Tue, 21 Jul 2020 20:48:07 -0400 Subject: [PATCH 056/344] MenuBar item header should be centered --- src/Avalonia.Themes.Fluent/Menu.xaml | 8 +++++--- src/Avalonia.Themes.Fluent/MenuItem.xaml | 9 ++++++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.Themes.Fluent/Menu.xaml b/src/Avalonia.Themes.Fluent/Menu.xaml index 5f22f77d18..cf647ec64a 100644 --- a/src/Avalonia.Themes.Fluent/Menu.xaml +++ b/src/Avalonia.Themes.Fluent/Menu.xaml @@ -10,11 +10,13 @@ - - 32 + + 32 + 12,0,12,0 + - + @@ -187,7 +189,12 @@ + + - + - + - - - - - - - - - - - - - - - - - - - - - - - - From 836a4d88c89c227f98b82abe38510ddb469cce36 Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Sat, 25 Jul 2020 20:37:45 +0200 Subject: [PATCH 097/344] Add missing style include for TitleBar in default theme. --- src/Avalonia.Themes.Default/DefaultTheme.xaml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Avalonia.Themes.Default/DefaultTheme.xaml b/src/Avalonia.Themes.Default/DefaultTheme.xaml index 97cff5d94b..4e63d1d223 100644 --- a/src/Avalonia.Themes.Default/DefaultTheme.xaml +++ b/src/Avalonia.Themes.Default/DefaultTheme.xaml @@ -37,6 +37,7 @@ + From 027783e3decf635ba2ba38033355563ebdfa832f Mon Sep 17 00:00:00 2001 From: Anton Mitsengendler Date: Sun, 26 Jul 2020 01:26:36 +0300 Subject: [PATCH 098/344] Added ComboBox placeholder to default theme template --- src/Avalonia.Themes.Default/ComboBox.xaml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Themes.Default/ComboBox.xaml b/src/Avalonia.Themes.Default/ComboBox.xaml index ae5b902ae8..8ee818bad2 100644 --- a/src/Avalonia.Themes.Default/ComboBox.xaml +++ b/src/Avalonia.Themes.Default/ComboBox.xaml @@ -1,4 +1,5 @@ - + @@ -24,6 +25,7 @@ + + Date: Sun, 26 Jul 2020 13:18:43 +0200 Subject: [PATCH 099/344] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 19a9a8420d..c1bf5bbfde 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,4 @@ -[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/AvaloniaUI/Avalonia?utm_campaign=pr-badge&utm_content=badge&utm_medium=badge&utm_source=badge) [![Build Status](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_apis/build/status/AvaloniaUI.Avalonia)](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_build/latest?definitionId=4) [![Backers on Open Collective](https://opencollective.com/Avalonia/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/Avalonia/sponsors/badge.svg)](#sponsors) ![License](https://img.shields.io/github/license/avaloniaui/avalonia.svg) +[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/AvaloniaUI/Avalonia?utm_campaign=pr-badge&utm_content=badge&utm_medium=badge&utm_source=badge) [![Discord](https://img.shields.io/badge/discord-join%20chat-46BC99)]( https://aka.ms/dotnet-discord) [![Build Status](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_apis/build/status/AvaloniaUI.Avalonia)](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_build/latest?definitionId=4) [![Backers on Open Collective](https://opencollective.com/Avalonia/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/Avalonia/sponsors/badge.svg)](#sponsors) ![License](https://img.shields.io/github/license/avaloniaui/avalonia.svg)
[![NuGet](https://img.shields.io/nuget/v/Avalonia.svg)](https://www.nuget.org/packages/Avalonia) [![downloads](https://img.shields.io/nuget/dt/avalonia)](https://www.nuget.org/packages/Avalonia) [![MyGet](https://img.shields.io/myget/avalonia-ci/vpre/Avalonia.svg?label=myget)](https://www.myget.org/gallery/avalonia-ci) ![Size](https://img.shields.io/github/repo-size/avaloniaui/avalonia.svg) From b04a1f78646099fa6f2a3dd4026ff2e7697d61cb Mon Sep 17 00:00:00 2001 From: Anton Mitsengendler Date: Sun, 26 Jul 2020 22:12:39 +0300 Subject: [PATCH 100/344] Changed resource name for a default placeholder foreground Added template binding for the placeholder foreground property to make it customizable from user code --- src/Avalonia.Themes.Default/ComboBox.xaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Themes.Default/ComboBox.xaml b/src/Avalonia.Themes.Default/ComboBox.xaml index 8ee818bad2..0fd6b144a4 100644 --- a/src/Avalonia.Themes.Default/ComboBox.xaml +++ b/src/Avalonia.Themes.Default/ComboBox.xaml @@ -25,7 +25,7 @@ - + Date: Mon, 27 Jul 2020 16:03:16 +0300 Subject: [PATCH 101/344] Enabled custom renderer factory for X11 and macOS --- src/Avalonia.Native/WindowImplBase.cs | 10 +++++++++- src/Avalonia.X11/X11Window.cs | 5 +++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Native/WindowImplBase.cs b/src/Avalonia.Native/WindowImplBase.cs index 42eecc36ea..4b13666edd 100644 --- a/src/Avalonia.Native/WindowImplBase.cs +++ b/src/Avalonia.Native/WindowImplBase.cs @@ -300,7 +300,15 @@ namespace Avalonia.Native public IRenderer CreateRenderer(IRenderRoot root) { if (_deferredRendering) - return new DeferredRenderer(root, AvaloniaLocator.Current.GetService()); + { + var loop = AvaloniaLocator.Current.GetService(); + var customRendererFactory = AvaloniaLocator.Current.GetService(); + + if (customRendererFactory != null) + return customRendererFactory.Create(root, loop); + return new DeferredRenderer(root, loop); + } + return new ImmediateRenderer(root); } diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index c24abcd230..0c0b942bcd 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -331,6 +331,11 @@ namespace Avalonia.X11 public IRenderer CreateRenderer(IRenderRoot root) { var loop = AvaloniaLocator.Current.GetService(); + var customRendererFactory = AvaloniaLocator.Current.GetService(); + + if (customRendererFactory != null) + return customRendererFactory.Create(root, loop); + return _platform.Options.UseDeferredRendering ? new DeferredRenderer(root, loop) : (IRenderer)new X11ImmediateRendererProxy(root, loop); From 8ac2e525ada5f667d77774dd5880efcbd7fc1bea Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Mon, 27 Jul 2020 16:03:40 +0300 Subject: [PATCH 102/344] Expose SKSurface from ISkiaDrawingContextImpl --- src/Skia/Avalonia.Skia/DrawingContextImpl.cs | 8 +++++--- src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs | 2 +- src/Skia/Avalonia.Skia/Gpu/ISkiaGpuRenderSession.cs | 2 +- src/Skia/Avalonia.Skia/Gpu/OpenGl/GlRenderTarget.cs | 2 +- src/Skia/Avalonia.Skia/Gpu/SkiaGpuRenderTarget.cs | 2 +- src/Skia/Avalonia.Skia/ISkiaDrawingContextImpl.cs | 1 + src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs | 2 +- 7 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index d818e683c3..b93d0f8868 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -44,7 +44,7 @@ namespace Avalonia.Skia /// /// Canvas to draw to. /// - public SKCanvas Canvas; + public SKSurface Surface; /// /// Dpi of drawings. @@ -81,8 +81,8 @@ namespace Avalonia.Skia _grContext = createInfo.GrContext; if (_grContext != null) Monitor.Enter(_grContext); - - Canvas = createInfo.Canvas; + Surface = createInfo.Surface; + Canvas = createInfo.Surface.Canvas; if (Canvas == null) { @@ -102,8 +102,10 @@ namespace Avalonia.Skia /// Skia canvas. /// public SKCanvas Canvas { get; } + public SKSurface Surface { get; } SKCanvas ISkiaDrawingContextImpl.SkCanvas => Canvas; + SKSurface ISkiaDrawingContextImpl.SkSurface => Surface; GRContext ISkiaDrawingContextImpl.GrContext => _grContext; /// diff --git a/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs b/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs index 8b04676b09..8d35d27a81 100644 --- a/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs +++ b/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs @@ -52,7 +52,7 @@ namespace Avalonia.Skia var createInfo = new DrawingContextImpl.CreateInfo { - Canvas = canvas, + Surface = _framebufferSurface, Dpi = framebuffer.Dpi, VisualBrushRenderer = visualBrushRenderer, DisableTextLcdRendering = true diff --git a/src/Skia/Avalonia.Skia/Gpu/ISkiaGpuRenderSession.cs b/src/Skia/Avalonia.Skia/Gpu/ISkiaGpuRenderSession.cs index c54d1bd859..a4e2bfed52 100644 --- a/src/Skia/Avalonia.Skia/Gpu/ISkiaGpuRenderSession.cs +++ b/src/Skia/Avalonia.Skia/Gpu/ISkiaGpuRenderSession.cs @@ -16,7 +16,7 @@ namespace Avalonia.Skia /// /// Canvas that will be used to render. /// - SKCanvas Canvas { get; } + SKSurface SkSurface { get; } /// /// Scaling factor. diff --git a/src/Skia/Avalonia.Skia/Gpu/OpenGl/GlRenderTarget.cs b/src/Skia/Avalonia.Skia/Gpu/OpenGl/GlRenderTarget.cs index e0b7019672..2bb739f372 100644 --- a/src/Skia/Avalonia.Skia/Gpu/OpenGl/GlRenderTarget.cs +++ b/src/Skia/Avalonia.Skia/Gpu/OpenGl/GlRenderTarget.cs @@ -49,7 +49,7 @@ namespace Avalonia.Skia } public GRContext GrContext { get; } - public SKCanvas Canvas => _surface.Canvas; + public SKSurface SkSurface => _surface; public double ScaleFactor => _glSession.Scaling; } diff --git a/src/Skia/Avalonia.Skia/Gpu/SkiaGpuRenderTarget.cs b/src/Skia/Avalonia.Skia/Gpu/SkiaGpuRenderTarget.cs index 94e513b2fd..ef5da5eb08 100644 --- a/src/Skia/Avalonia.Skia/Gpu/SkiaGpuRenderTarget.cs +++ b/src/Skia/Avalonia.Skia/Gpu/SkiaGpuRenderTarget.cs @@ -27,7 +27,7 @@ namespace Avalonia.Skia var nfo = new DrawingContextImpl.CreateInfo { GrContext = session.GrContext, - Canvas = session.Canvas, + Surface = session.SkSurface, Dpi = SkiaPlatform.DefaultDpi * session.ScaleFactor, VisualBrushRenderer = visualBrushRenderer, DisableTextLcdRendering = true diff --git a/src/Skia/Avalonia.Skia/ISkiaDrawingContextImpl.cs b/src/Skia/Avalonia.Skia/ISkiaDrawingContextImpl.cs index a9b91384d7..38fa5a5253 100644 --- a/src/Skia/Avalonia.Skia/ISkiaDrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/ISkiaDrawingContextImpl.cs @@ -7,5 +7,6 @@ namespace Avalonia.Skia { SKCanvas SkCanvas { get; } GRContext GrContext { get; } + SKSurface SkSurface { get; } } } diff --git a/src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs b/src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs index 588f7bee6c..27b29c6e1e 100644 --- a/src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs +++ b/src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs @@ -70,7 +70,7 @@ namespace Avalonia.Skia var createInfo = new DrawingContextImpl.CreateInfo { - Canvas = _canvas, + Surface = _surface, Dpi = Dpi, VisualBrushRenderer = visualBrushRenderer, DisableTextLcdRendering = _disableLcdRendering, From 2bec4c14c5b77bf2b94f5943d311d18b78d2ce1b Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Mon, 27 Jul 2020 15:14:10 +0200 Subject: [PATCH 103/344] Fixes SKFontStyleSlant to FontStyle conversion --- src/Avalonia.Visuals/Media/FontStyle.cs | 8 ++++---- src/Skia/Avalonia.Skia/SKTypefaceCollectionCache.cs | 3 ++- src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs | 11 +++++++++++ 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/Avalonia.Visuals/Media/FontStyle.cs b/src/Avalonia.Visuals/Media/FontStyle.cs index cbc92b1a9f..b9d04bf9ff 100644 --- a/src/Avalonia.Visuals/Media/FontStyle.cs +++ b/src/Avalonia.Visuals/Media/FontStyle.cs @@ -11,13 +11,13 @@ namespace Avalonia.Media Normal, /// - /// An oblique font. + /// An italic font. /// - Oblique, + Italic, /// - /// An italic font. + /// An oblique font. /// - Italic, + Oblique } } diff --git a/src/Skia/Avalonia.Skia/SKTypefaceCollectionCache.cs b/src/Skia/Avalonia.Skia/SKTypefaceCollectionCache.cs index d36baf331d..7ca44e7282 100644 --- a/src/Skia/Avalonia.Skia/SKTypefaceCollectionCache.cs +++ b/src/Skia/Avalonia.Skia/SKTypefaceCollectionCache.cs @@ -56,7 +56,8 @@ namespace Avalonia.Skia continue; } - var key = new FontKey(fontFamily.Name, (FontStyle)typeface.FontSlant, (FontWeight)typeface.FontWeight); + var key = new FontKey(fontFamily.Name, typeface.FontSlant.ToAvalonia(), + (FontWeight)typeface.FontWeight); typeFaceCollection.AddTypeface(key, typeface); } diff --git a/src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs b/src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs index ec7e0a67ed..1e772ef067 100644 --- a/src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs +++ b/src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs @@ -138,6 +138,17 @@ namespace Avalonia.Skia } } + public static FontStyle ToAvalonia(this SKFontStyleSlant slant) + { + return slant switch + { + SKFontStyleSlant.Upright => FontStyle.Normal, + SKFontStyleSlant.Italic => FontStyle.Italic, + SKFontStyleSlant.Oblique => FontStyle.Oblique, + _ => throw new ArgumentOutOfRangeException(nameof (slant), slant, null) + }; + } + public static SKPath Clone(this SKPath src) { return src != null ? new SKPath(src) : null; From 63fd7471ec4d58caab6a840515fadbbe41386e7c Mon Sep 17 00:00:00 2001 From: Splitwirez Date: Mon, 27 Jul 2020 10:07:39 -0400 Subject: [PATCH 104/344] Yeeted aerohost check --- src/Windows/Avalonia.Win32/WindowImpl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 30c4bf85a9..cae4b5307e 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -309,7 +309,7 @@ namespace Avalonia.Win32 Marshal.FreeHGlobal(accentPtr); - if ((transparencyLevel >= WindowTransparencyLevel.Blur) && (Process.GetProcessesByName("aerohost").Length > 0)) //Use Windows 7 blur if the Aero glass mod is installed, since that's exactly what the mod does + if (transparencyLevel >= WindowTransparencyLevel.Blur) //Use Windows 7 blur logic, which will produce blur if the Aero glass mod is installed and will merely look kinda stupid if not Win7EnableBlur(transparencyLevel); return transparencyLevel; From 54553b44d39d7e32d7980da4b7d9276bdbd69b94 Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Mon, 27 Jul 2020 16:48:41 +0200 Subject: [PATCH 105/344] Make npm silent --- nukebuild/Build.cs | 4 +++- .../Remote/HtmlTransport/webapp/webpack.config.js | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/nukebuild/Build.cs b/nukebuild/Build.cs index fe877dc49c..fbfbf47e1b 100644 --- a/nukebuild/Build.cs +++ b/nukebuild/Build.cs @@ -128,7 +128,9 @@ partial class Build : NukeBuild { var webappDir = RootDirectory / "src" / "Avalonia.DesignerSupport" / "Remote" / "HtmlTransport" / "webapp"; - NpmTasks.NpmInstall(c => c.SetWorkingDirectory(webappDir)); + NpmTasks.NpmInstall(c => c + .SetWorkingDirectory(webappDir) + .SetArgumentConfigurator(a => a.Add("--silent"))); NpmTasks.NpmRun(c => c .SetWorkingDirectory(webappDir) .SetCommand("dist")); diff --git a/src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/webpack.config.js b/src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/webpack.config.js index 3057f269a5..3750351165 100644 --- a/src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/webpack.config.js +++ b/src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/webpack.config.js @@ -93,7 +93,7 @@ const config = { plugins: [ new Printer(), - new CleanWebpackPlugin([path.resolve(__dirname, 'build')]), + new CleanWebpackPlugin([path.resolve(__dirname, 'build')], { verbose: false }), new MiniCssExtractPlugin({ filename: "[name].[chunkhash]h" + ".css", From 8e1443384f5b8323178a5102e3fcdb1891008f5f Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Mon, 27 Jul 2020 17:25:33 +0200 Subject: [PATCH 106/344] Add app compat baseline --- src/Avalonia.Visuals/ApiCompatBaseline.txt | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 src/Avalonia.Visuals/ApiCompatBaseline.txt diff --git a/src/Avalonia.Visuals/ApiCompatBaseline.txt b/src/Avalonia.Visuals/ApiCompatBaseline.txt new file mode 100644 index 0000000000..00618448a2 --- /dev/null +++ b/src/Avalonia.Visuals/ApiCompatBaseline.txt @@ -0,0 +1,4 @@ +Compat issues with assembly Avalonia.Visuals: +EnumValuesMustMatch : Enum value 'Avalonia.Media.FontStyle Avalonia.Media.FontStyle.Italic' is (System.Int32)1 in the implementation but (System.Int32)2 in the contract. +EnumValuesMustMatch : Enum value 'Avalonia.Media.FontStyle Avalonia.Media.FontStyle.Oblique' is (System.Int32)2 in the implementation but (System.Int32)1 in the contract. +Total Issues: 2 From 385dd5227155342ed5c1fb142bcbfcce21312584 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Mon, 27 Jul 2020 13:33:15 -0300 Subject: [PATCH 107/344] remove apicompat from backend impl checks. --- .../Avalonia.LinuxFramebuffer/Avalonia.LinuxFramebuffer.csproj | 3 +-- src/Skia/Avalonia.Skia/Avalonia.Skia.csproj | 3 +-- src/Windows/Avalonia.Win32/Avalonia.Win32.csproj | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Avalonia.LinuxFramebuffer.csproj b/src/Linux/Avalonia.LinuxFramebuffer/Avalonia.LinuxFramebuffer.csproj index 22599200bc..48095a4c25 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/Avalonia.LinuxFramebuffer.csproj +++ b/src/Linux/Avalonia.LinuxFramebuffer/Avalonia.LinuxFramebuffer.csproj @@ -7,6 +7,5 @@ - - + diff --git a/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj b/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj index ef955eb8be..ac029f1062 100644 --- a/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj +++ b/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj @@ -16,6 +16,5 @@ - - + diff --git a/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj b/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj index bcbdde322c..7fc24d4d3d 100644 --- a/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj +++ b/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj @@ -8,6 +8,5 @@ - - + From 307ab82292bf4eed46e390e7d77def7acc28cbcb Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Mon, 27 Jul 2020 13:37:01 -0300 Subject: [PATCH 108/344] remove opengl apicompat checks. --- src/Avalonia.OpenGL/Avalonia.OpenGL.csproj | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Avalonia.OpenGL/Avalonia.OpenGL.csproj b/src/Avalonia.OpenGL/Avalonia.OpenGL.csproj index 2e23f24deb..d761e60c07 100644 --- a/src/Avalonia.OpenGL/Avalonia.OpenGL.csproj +++ b/src/Avalonia.OpenGL/Avalonia.OpenGL.csproj @@ -9,7 +9,5 @@ - - - + From d759435c05a089086484d664752b5a35297e903d Mon Sep 17 00:00:00 2001 From: Rustam Sayfutdinov Date: Mon, 27 Jul 2020 21:52:51 +0300 Subject: [PATCH 109/344] Reverts changing colors for default theme by '36c5ad4621d372cf932f1259c77a23c4d1cb6962' --- src/Avalonia.Themes.Default/TitleBar.xaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Themes.Default/TitleBar.xaml b/src/Avalonia.Themes.Default/TitleBar.xaml index 4dba5b4ba4..7f8ed24076 100644 --- a/src/Avalonia.Themes.Default/TitleBar.xaml +++ b/src/Avalonia.Themes.Default/TitleBar.xaml @@ -5,7 +5,7 @@ diff --git a/src/Avalonia.Themes.Fluent/DataValidationErrors.xaml b/src/Avalonia.Themes.Fluent/DataValidationErrors.xaml index f4145a51f5..88c6b661f1 100644 --- a/src/Avalonia.Themes.Fluent/DataValidationErrors.xaml +++ b/src/Avalonia.Themes.Fluent/DataValidationErrors.xaml @@ -1,5 +1,16 @@ - + diff --git a/src/Avalonia.Themes.Fluent/TextBox.xaml b/src/Avalonia.Themes.Fluent/TextBox.xaml index 0327e776e3..be5e21d03d 100644 --- a/src/Avalonia.Themes.Fluent/TextBox.xaml +++ b/src/Avalonia.Themes.Fluent/TextBox.xaml @@ -1,4 +1,13 @@ + + + + + + 0,0,0,4 @@ -42,7 +51,7 @@ @@ -136,7 +145,7 @@ diff --git a/samples/ControlCatalog/App.xaml.cs b/samples/ControlCatalog/App.xaml.cs index 3f1ec289d1..b0fbcc76d2 100644 --- a/samples/ControlCatalog/App.xaml.cs +++ b/samples/ControlCatalog/App.xaml.cs @@ -67,9 +67,9 @@ namespace ControlCatalog public override void Initialize() { - AvaloniaXamlLoader.Load(this); - Styles.Insert(0, FluentDark); + + AvaloniaXamlLoader.Load(this); } public override void OnFrameworkInitializationCompleted() diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml index af95e3c356..efc90357ed 100644 --- a/samples/ControlCatalog/MainView.xaml +++ b/samples/ControlCatalog/MainView.xaml @@ -1,9 +1,7 @@ + x:Class="ControlCatalog.MainView"> diff --git a/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml b/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml index 304782dbf9..392ccb57c3 100644 --- a/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml +++ b/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml @@ -43,7 +43,7 @@ - + diff --git a/samples/ControlCatalog/Pages/ScreenPage.cs b/samples/ControlCatalog/Pages/ScreenPage.cs index d775eb9635..c39f414b44 100644 --- a/samples/ControlCatalog/Pages/ScreenPage.cs +++ b/samples/ControlCatalog/Pages/ScreenPage.cs @@ -29,7 +29,8 @@ namespace ControlCatalog.Pages var screens = w.Screens.All; var scaling = ((IRenderRoot)w).RenderScaling; - Pen p = new Pen(Brushes.Black); + var drawBrush = Brushes.Green; + Pen p = new Pen(drawBrush); if (screens != null) foreach (Screen screen in screens) { @@ -53,19 +54,19 @@ namespace ControlCatalog.Pages }; text.Text = $"Bounds: {screen.Bounds.Width}:{screen.Bounds.Height}"; - context.DrawText(Brushes.Black, boundsRect.Position.WithY(boundsRect.Size.Height), text); + context.DrawText(drawBrush, boundsRect.Position.WithY(boundsRect.Size.Height), text); text.Text = $"WorkArea: {screen.WorkingArea.Width}:{screen.WorkingArea.Height}"; - context.DrawText(Brushes.Black, boundsRect.Position.WithY(boundsRect.Size.Height + 20), text); + context.DrawText(drawBrush, boundsRect.Position.WithY(boundsRect.Size.Height + 20), text); text.Text = $"Scaling: {screen.PixelDensity * 100}%"; - context.DrawText(Brushes.Black, boundsRect.Position.WithY(boundsRect.Size.Height + 40), text); + context.DrawText(drawBrush, boundsRect.Position.WithY(boundsRect.Size.Height + 40), text); text.Text = $"Primary: {screen.Primary}"; - context.DrawText(Brushes.Black, boundsRect.Position.WithY(boundsRect.Size.Height + 60), text); + context.DrawText(drawBrush, boundsRect.Position.WithY(boundsRect.Size.Height + 60), text); text.Text = $"Current: {screen.Equals(w.Screens.ScreenFromBounds(new PixelRect(w.Position, PixelSize.FromSize(w.Bounds.Size, scaling))))}"; - context.DrawText(Brushes.Black, boundsRect.Position.WithY(boundsRect.Size.Height + 80), text); + context.DrawText(drawBrush, boundsRect.Position.WithY(boundsRect.Size.Height + 80), text); } context.DrawRectangle(p, new Rect(w.Position.X / 10f + Math.Abs(_leftMost), w.Position.Y / 10, w.Bounds.Width / 10, w.Bounds.Height / 10)); diff --git a/samples/ControlCatalog/Pages/TextBlockPage.xaml b/samples/ControlCatalog/Pages/TextBlockPage.xaml index 4b8edcf98c..4a1c196917 100644 --- a/samples/ControlCatalog/Pages/TextBlockPage.xaml +++ b/samples/ControlCatalog/Pages/TextBlockPage.xaml @@ -12,7 +12,7 @@ @@ -49,7 +49,7 @@ From 037e63d9ab7145893b684b28d2ec62ed614a8a92 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 30 Jul 2020 10:48:29 -0300 Subject: [PATCH 132/344] add unit test for specific scenario where datacontext changes tip before remvoed from visual tree. --- .../ToolTipTests.cs | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/tests/Avalonia.Controls.UnitTests/ToolTipTests.cs b/tests/Avalonia.Controls.UnitTests/ToolTipTests.cs index 67df6343af..e52e7a487b 100644 --- a/tests/Avalonia.Controls.UnitTests/ToolTipTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ToolTipTests.cs @@ -1,5 +1,6 @@ using System; using System.Reactive.Disposables; +using Avalonia.Markup.Xaml; using Avalonia.Platform; using Avalonia.Threading; using Avalonia.UnitTests; @@ -66,34 +67,33 @@ namespace Avalonia.Controls.UnitTests } [Fact] - public void Should_Close_When_Tip_Is_Changed() + public void Should_Close_When_Tip_Is_Opened_And_Detached_From_Visual_Tree() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { - var window = new Window(); - - var panel = new Panel(); - - var target = new Decorator() - { - [ToolTip.TipProperty] = "Tip", - [ToolTip.ShowDelayProperty] = 0 - }; + var xaml = @" + + + + +"; + var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); - panel.Children.Add(target); - - window.Content = panel; - + window.DataContext = new ToolTipViewModel(); window.ApplyTemplate(); window.Presenter.ApplyTemplate(); + var target = window.Find("PART_target"); + var panel = window.Find("PART_panel"); + Assert.True((target as IVisual).IsAttachedToVisualTree); _mouseHelper.Enter(target); Assert.True(ToolTip.GetIsOpen(target)); - - ToolTip.SetTip(target, ""); + + panel.Children.Remove(target); Assert.False(ToolTip.GetIsOpen(target)); } @@ -242,4 +242,9 @@ namespace Avalonia.Controls.UnitTests } } } + + internal class ToolTipViewModel + { + public string Tip => "Tip"; + } } From eb132105e43adef9ce6d2feb4675dbab30b1904d Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 30 Jul 2020 10:52:47 -0300 Subject: [PATCH 133/344] restore tooltipservice. failing unit test. --- src/Avalonia.Controls/ToolTipService.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Avalonia.Controls/ToolTipService.cs b/src/Avalonia.Controls/ToolTipService.cs index 587bbb6aa6..569697304f 100644 --- a/src/Avalonia.Controls/ToolTipService.cs +++ b/src/Avalonia.Controls/ToolTipService.cs @@ -29,7 +29,6 @@ namespace Avalonia.Controls control.PointerEnter -= ControlPointerEnter; control.PointerLeave -= ControlPointerLeave; control.DetachedFromVisualTree -= ControlDetaching; - Close(control); } if (e.NewValue != null) From 49e41b959438fa4ccab96fcc4b18cef696b859c9 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 30 Jul 2020 13:00:05 -0300 Subject: [PATCH 134/344] prevent tooltipgetting stuck. --- src/Avalonia.Controls/ToolTip.cs | 1 + src/Avalonia.Controls/ToolTipService.cs | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/ToolTip.cs b/src/Avalonia.Controls/ToolTip.cs index b458b15c64..cf0652247f 100644 --- a/src/Avalonia.Controls/ToolTip.cs +++ b/src/Avalonia.Controls/ToolTip.cs @@ -66,6 +66,7 @@ namespace Avalonia.Controls static ToolTip() { TipProperty.Changed.Subscribe(ToolTipService.Instance.TipChanged); + IsOpenProperty.Changed.Subscribe(ToolTipService.Instance.TipOpenChanged); IsOpenProperty.Changed.Subscribe(IsOpenChanged); } diff --git a/src/Avalonia.Controls/ToolTipService.cs b/src/Avalonia.Controls/ToolTipService.cs index 569697304f..e2a0f9e50c 100644 --- a/src/Avalonia.Controls/ToolTipService.cs +++ b/src/Avalonia.Controls/ToolTipService.cs @@ -28,20 +28,33 @@ namespace Avalonia.Controls { control.PointerEnter -= ControlPointerEnter; control.PointerLeave -= ControlPointerLeave; - control.DetachedFromVisualTree -= ControlDetaching; } if (e.NewValue != null) { control.PointerEnter += ControlPointerEnter; control.PointerLeave += ControlPointerLeave; + } + } + + internal void TipOpenChanged(AvaloniaPropertyChangedEventArgs e) + { + var control = (Control)e.Sender; + + if (e.OldValue is false && e.NewValue is true) + { control.DetachedFromVisualTree += ControlDetaching; } + else if(e.OldValue is true && e.NewValue is false) + { + control.DetachedFromVisualTree -= ControlDetaching; + } } private void ControlDetaching(object sender, VisualTreeAttachmentEventArgs e) { var control = (Control)sender; + control.DetachedFromVisualTree -= ControlDetaching; Close(control); } From 972587130b806a0f84795bc6b78ca9c990469dc1 Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Thu, 9 Jul 2020 23:35:30 +0200 Subject: [PATCH 135/344] Support passing alpha format to created bitmaps. --- samples/RenderDemo/MainWindow.xaml | 3 + .../RenderDemo/Pages/WriteableBitmapPage.cs | 92 +++++++++++++++++++ src/Avalonia.Visuals/Media/Imaging/Bitmap.cs | 5 +- .../Media/Imaging/WriteableBitmap.cs | 5 +- src/Avalonia.Visuals/Platform/AlphaFormat.cs | 9 ++ .../Platform/IPlatformRenderInterface.cs | 7 +- src/Skia/Avalonia.Skia/ImmutableBitmap.cs | 9 +- .../Avalonia.Skia/PlatformRenderInterface.cs | 10 +- src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs | 22 +++++ src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs | 9 +- .../Avalonia.Direct2D1/Direct2D1Platform.cs | 13 +-- .../Media/Imaging/WicBitmapImpl.cs | 17 ++-- .../Media/Imaging/WriteableWicBitmapImpl.cs | 4 +- .../Avalonia.Direct2D1/PrimitiveExtensions.cs | 9 +- 14 files changed, 172 insertions(+), 42 deletions(-) create mode 100644 samples/RenderDemo/Pages/WriteableBitmapPage.cs create mode 100644 src/Avalonia.Visuals/Platform/AlphaFormat.cs diff --git a/samples/RenderDemo/MainWindow.xaml b/samples/RenderDemo/MainWindow.xaml index 14ccc82043..770960d7c4 100644 --- a/samples/RenderDemo/MainWindow.xaml +++ b/samples/RenderDemo/MainWindow.xaml @@ -44,6 +44,9 @@ + + + diff --git a/samples/RenderDemo/Pages/WriteableBitmapPage.cs b/samples/RenderDemo/Pages/WriteableBitmapPage.cs new file mode 100644 index 0000000000..850e398a93 --- /dev/null +++ b/samples/RenderDemo/Pages/WriteableBitmapPage.cs @@ -0,0 +1,92 @@ +using System.Diagnostics; +using System.Runtime.InteropServices; +using Avalonia; +using Avalonia.Controls; +using Avalonia.LogicalTree; +using Avalonia.Media; +using Avalonia.Media.Imaging; +using Avalonia.Media.Immutable; +using Avalonia.Platform; +using Avalonia.Threading; + +namespace RenderDemo.Pages +{ + public class WriteableBitmapPage : Control + { + private WriteableBitmap _unpremulBitmap; + private WriteableBitmap _premulBitmap; + private readonly Stopwatch _st = Stopwatch.StartNew(); + + protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e) + { + _unpremulBitmap = new WriteableBitmap(new PixelSize(256, 256), new Vector(96, 96), PixelFormat.Bgra8888, AlphaFormat.Unpremul); + _premulBitmap = new WriteableBitmap(new PixelSize(256, 256), new Vector(96, 96), PixelFormat.Bgra8888, AlphaFormat.Premul); + + base.OnAttachedToLogicalTree(e); + } + + protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e) + { + base.OnDetachedFromLogicalTree(e); + + _unpremulBitmap?.Dispose(); + _unpremulBitmap = null; + + _premulBitmap?.Dispose(); + _unpremulBitmap = null; + } + + public override void Render(DrawingContext context) + { + void FillPixels(WriteableBitmap bitmap, byte fillAlpha, bool premul) + { + using (var fb = bitmap.Lock()) + { + var data = new int[fb.Size.Width * fb.Size.Height]; + + for (int y = 0; y < fb.Size.Height; y++) + { + for (int x = 0; x < fb.Size.Width; x++) + { + var color = new Color(fillAlpha, 0, 255, 0); + + if (premul) + { + byte r = (byte) (color.R * color.A / 255); + byte g = (byte) (color.G * color.A / 255); + byte b = (byte) (color.B * color.A / 255); + + color = new Color(fillAlpha, r, g, b); + } + + data[y * fb.Size.Width + x] = (int) color.ToUint32(); + } + } + + Marshal.Copy(data, 0, fb.Address, fb.Size.Width * fb.Size.Height); + } + } + + base.Render(context); + + byte alpha = (byte)((_st.ElapsedMilliseconds / 10) % 256); + + FillPixels(_unpremulBitmap, alpha, false); + FillPixels(_premulBitmap, alpha, true); + + context.FillRectangle(Brushes.Red, new Rect(0, 0, 256 * 3, 256)); + + context.DrawImage(_unpremulBitmap, + new Rect(0, 0, 256, 256), + new Rect(0, 0, 256, 256)); + + context.DrawImage(_premulBitmap, + new Rect(0, 0, 256, 256), + new Rect(256, 0, 256, 256)); + + context.FillRectangle(new ImmutableSolidColorBrush(Colors.Lime, alpha / 255d), new Rect(512, 0, 256, 256)); + + Dispatcher.UIThread.Post(InvalidateVisual, DispatcherPriority.Background); + } + } +} diff --git a/src/Avalonia.Visuals/Media/Imaging/Bitmap.cs b/src/Avalonia.Visuals/Media/Imaging/Bitmap.cs index 86e2700c04..f86ce326d5 100644 --- a/src/Avalonia.Visuals/Media/Imaging/Bitmap.cs +++ b/src/Avalonia.Visuals/Media/Imaging/Bitmap.cs @@ -99,14 +99,15 @@ namespace Avalonia.Media.Imaging /// Initializes a new instance of the class. /// /// The pixel format. + /// The alpha format. /// The pointer to the source bytes. /// The size of the bitmap in device pixels. /// The DPI of the bitmap. /// The number of bytes per row. - public Bitmap(PixelFormat format, IntPtr data, PixelSize size, Vector dpi, int stride) + public Bitmap(PixelFormat format, AlphaFormat alphaFormat, IntPtr data, PixelSize size, Vector dpi, int stride) { PlatformImpl = RefCountable.Create(AvaloniaLocator.Current.GetService() - .LoadBitmap(format, data, size, dpi, stride)); + .LoadBitmap(format, alphaFormat, data, size, dpi, stride)); } /// diff --git a/src/Avalonia.Visuals/Media/Imaging/WriteableBitmap.cs b/src/Avalonia.Visuals/Media/Imaging/WriteableBitmap.cs index 88c0799cb9..b93706e6e5 100644 --- a/src/Avalonia.Visuals/Media/Imaging/WriteableBitmap.cs +++ b/src/Avalonia.Visuals/Media/Imaging/WriteableBitmap.cs @@ -13,9 +13,10 @@ namespace Avalonia.Media.Imaging /// The size of the bitmap in device pixels. /// The DPI of the bitmap. /// The pixel format (optional). + /// The alpha format (optional). /// An . - public WriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null) - : base(AvaloniaLocator.Current.GetService().CreateWriteableBitmap(size, dpi, format)) + public WriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null, AlphaFormat? alphaFormat = null) + : base(AvaloniaLocator.Current.GetService().CreateWriteableBitmap(size, dpi, format, alphaFormat)) { } diff --git a/src/Avalonia.Visuals/Platform/AlphaFormat.cs b/src/Avalonia.Visuals/Platform/AlphaFormat.cs new file mode 100644 index 0000000000..ce8dcde728 --- /dev/null +++ b/src/Avalonia.Visuals/Platform/AlphaFormat.cs @@ -0,0 +1,9 @@ +namespace Avalonia.Platform +{ + public enum AlphaFormat + { + Premul, + Unpremul, + Opaque + } +} diff --git a/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs b/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs index ba30272b7b..5906d4080e 100644 --- a/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs +++ b/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.IO; using Avalonia.Media; -using Avalonia.Media.Imaging; using Avalonia.Visuals.Media.Imaging; namespace Avalonia.Platform @@ -83,8 +82,9 @@ namespace Avalonia.Platform /// The size of the bitmap in device pixels. /// The DPI of the bitmap. /// Pixel format (optional). + /// Alpha format (optional). /// An . - IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null); + IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null, AlphaFormat? alphaFormat = null); /// /// Loads a bitmap implementation from a file.. @@ -124,12 +124,13 @@ namespace Avalonia.Platform /// Loads a bitmap implementation from a pixels in memory. /// /// The pixel format. + /// The alpha format. /// The pointer to source bytes. /// The size of the bitmap in device pixels. /// The DPI of the bitmap. /// The number of bytes per row. /// An . - IBitmapImpl LoadBitmap(PixelFormat format, IntPtr data, PixelSize size, Vector dpi, int stride); + IBitmapImpl LoadBitmap(PixelFormat format, AlphaFormat alphaFormat, IntPtr data, PixelSize size, Vector dpi, int stride); /// /// Creates a platform implementation of a glyph run. diff --git a/src/Skia/Avalonia.Skia/ImmutableBitmap.cs b/src/Skia/Avalonia.Skia/ImmutableBitmap.cs index e84c7e34de..3010f49420 100644 --- a/src/Skia/Avalonia.Skia/ImmutableBitmap.cs +++ b/src/Skia/Avalonia.Skia/ImmutableBitmap.cs @@ -85,10 +85,6 @@ namespace Avalonia.Skia if (bmp.Width != desired.Width || bmp.Height != desired.Height) { - if (bmp.Height != bmp.Width) - { - - } var scaledBmp = bmp.Resize(desired, interpolationMode.ToSKFilterQuality()); bmp.Dispose(); bmp = scaledBmp; @@ -116,10 +112,11 @@ namespace Avalonia.Skia /// DPI of the bitmap. /// Stride of data pixels. /// Format of data pixels. + /// Alpha format of data pixels. /// Data pixels. - public ImmutableBitmap(PixelSize size, Vector dpi, int stride, PixelFormat format, IntPtr data) + public ImmutableBitmap(PixelSize size, Vector dpi, int stride, PixelFormat format, AlphaFormat alphaFormat, IntPtr data) { - var imageInfo = new SKImageInfo(size.Width, size.Height, format.ToSkColorType(), SKAlphaType.Premul); + var imageInfo = new SKImageInfo(size.Width, size.Height, format.ToSkColorType(), alphaFormat.ToSkAlphaType()); _image = SKImage.FromPixelCopy(imageInfo, data, stride); diff --git a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs index 66b7fdea13..8c53ac2b4e 100644 --- a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs +++ b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs @@ -2,11 +2,9 @@ using System; using System.Collections; using System.Collections.Generic; using System.IO; -using System.Security.Cryptography; using System.Linq; using Avalonia.Controls.Platform.Surfaces; using Avalonia.Media; -using Avalonia.Media.Imaging; using Avalonia.OpenGL; using Avalonia.OpenGL.Imaging; using Avalonia.Platform; @@ -76,9 +74,9 @@ namespace Avalonia.Skia } /// - public IBitmapImpl LoadBitmap(PixelFormat format, IntPtr data, PixelSize size, Vector dpi, int stride) + public IBitmapImpl LoadBitmap(PixelFormat format, AlphaFormat alphaFormat, IntPtr data, PixelSize size, Vector dpi, int stride) { - return new ImmutableBitmap(size, dpi, stride, format, data); + return new ImmutableBitmap(size, dpi, stride, format, alphaFormat, data); } /// @@ -152,9 +150,9 @@ namespace Avalonia.Skia } /// - public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null) + public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null, AlphaFormat? alphaFormat = null) { - return new WriteableBitmapImpl(size, dpi, format); + return new WriteableBitmapImpl(size, dpi, format, alphaFormat); } private static readonly SKFont s_font = new SKFont diff --git a/src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs b/src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs index 1e772ef067..bb3dbbfadc 100644 --- a/src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs +++ b/src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs @@ -105,6 +105,28 @@ namespace Avalonia.Skia throw new ArgumentException("Unknown pixel format: " + fmt); } + public static SKAlphaType ToSkAlphaType(this AlphaFormat fmt) + { + return fmt switch + { + AlphaFormat.Premul => SKAlphaType.Premul, + AlphaFormat.Unpremul => SKAlphaType.Unpremul, + AlphaFormat.Opaque => SKAlphaType.Opaque, + _ => throw new ArgumentException($"Unknown alpha format: {fmt}") + }; + } + + public static AlphaFormat ToAlphaFormat(this SKAlphaType fmt) + { + return fmt switch + { + SKAlphaType.Premul => AlphaFormat.Premul, + SKAlphaType.Unpremul => AlphaFormat.Unpremul, + SKAlphaType.Opaque => AlphaFormat.Opaque, + _ => throw new ArgumentException($"Unknown alpha format: {fmt}") + }; + } + public static SKShaderTileMode ToSKShaderTileMode(this Media.GradientSpreadMethod m) { switch (m) diff --git a/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs b/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs index 9bdd30f40b..3c29bf65ed 100644 --- a/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs +++ b/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs @@ -22,12 +22,15 @@ namespace Avalonia.Skia /// The size of the bitmap in device pixels. /// The DPI of the bitmap. /// The pixel format. - public WriteableBitmapImpl(PixelSize size, Vector dpi, PixelFormat? format = null) + /// The alpha format. + public WriteableBitmapImpl(PixelSize size, Vector dpi, PixelFormat? format = null, AlphaFormat? alphaFormat = null) { PixelSize = size; Dpi = dpi; var colorType = PixelFormatHelper.ResolveColorType(format); + + SKAlphaType alphaType = alphaFormat?.ToSkAlphaType() ?? SKAlphaType.Premul; var runtimePlatform = AvaloniaLocator.Current?.GetService(); @@ -35,14 +38,14 @@ namespace Avalonia.Skia { _bitmap = new SKBitmap(); - var nfo = new SKImageInfo(size.Width, size.Height, colorType, SKAlphaType.Premul); + var nfo = new SKImageInfo(size.Width, size.Height, colorType, alphaType); var blob = runtimePlatform.AllocBlob(nfo.BytesSize); _bitmap.InstallPixels(nfo, blob.Address, nfo.RowBytes, s_releaseDelegate, blob); } else { - _bitmap = new SKBitmap(size.Width, size.Height, colorType, SKAlphaType.Premul); + _bitmap = new SKBitmap(size.Width, size.Height, colorType, alphaType); } _bitmap.Erase(SKColor.Empty); diff --git a/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs b/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs index c4c0541d53..047cd7a13b 100644 --- a/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs +++ b/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs @@ -115,11 +115,6 @@ namespace Avalonia.Direct2D1 SharpDX.Configuration.EnableReleaseOnFinalizer = true; } - public IBitmapImpl CreateBitmap(PixelSize size, Vector dpi) - { - return new WicBitmapImpl(size, dpi); - } - public IFormattedTextImpl CreateFormattedText( string text, Typeface typeface, @@ -171,9 +166,9 @@ namespace Avalonia.Direct2D1 return new WicRenderTargetBitmapImpl(size, dpi); } - public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null) + public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null, AlphaFormat? alphaFormat = null) { - return new WriteableWicBitmapImpl(size, dpi, format); + return new WriteableWicBitmapImpl(size, dpi, format, alphaFormat); } public IGeometryImpl CreateEllipseGeometry(Rect rect) => new EllipseGeometryImpl(rect); @@ -213,9 +208,9 @@ namespace Avalonia.Direct2D1 } /// - public IBitmapImpl LoadBitmap(PixelFormat format, IntPtr data, PixelSize size, Vector dpi, int stride) + public IBitmapImpl LoadBitmap(PixelFormat format, AlphaFormat alphaFormat, IntPtr data, PixelSize size, Vector dpi, int stride) { - return new WicBitmapImpl(format, data, size, dpi, stride); + return new WicBitmapImpl(format, alphaFormat, data, size, dpi, stride); } public IGlyphRunImpl CreateGlyphRun(GlyphRun glyphRun, out double width) diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs index 743abddd1e..49193afd78 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs @@ -1,9 +1,9 @@ using System; using System.IO; -using System.Security.Cryptography; using Avalonia.Win32.Interop; using SharpDX.WIC; using APixelFormat = Avalonia.Platform.PixelFormat; +using AlphaFormat = Avalonia.Platform.AlphaFormat; using D2DBitmap = SharpDX.Direct2D1.Bitmap; namespace Avalonia.Direct2D1.Media @@ -73,29 +73,34 @@ namespace Avalonia.Direct2D1.Media /// The size of the bitmap in device pixels. /// The DPI of the bitmap. /// Pixel format - public WicBitmapImpl(PixelSize size, Vector dpi, APixelFormat? pixelFormat = null) + /// Alpha format. + public WicBitmapImpl(PixelSize size, Vector dpi, APixelFormat? pixelFormat = null, AlphaFormat? alphaFormat = null) { if (!pixelFormat.HasValue) { pixelFormat = APixelFormat.Bgra8888; } + if (!alphaFormat.HasValue) + { + alphaFormat = AlphaFormat.Premul; + } + PixelFormat = pixelFormat; WicImpl = new Bitmap( Direct2D1Platform.ImagingFactory, size.Width, size.Height, - pixelFormat.Value.ToWic(), + pixelFormat.Value.ToWic(alphaFormat.Value), BitmapCreateCacheOption.CacheOnLoad); Dpi = dpi; } - public WicBitmapImpl(APixelFormat format, IntPtr data, PixelSize size, Vector dpi, int stride) + public WicBitmapImpl(APixelFormat format, AlphaFormat alphaFormat, IntPtr data, PixelSize size, Vector dpi, int stride) { - WicImpl = new Bitmap(Direct2D1Platform.ImagingFactory, size.Width, size.Height, format.ToWic(), BitmapCreateCacheOption.CacheOnDemand); + WicImpl = new Bitmap(Direct2D1Platform.ImagingFactory, size.Width, size.Height, format.ToWic(alphaFormat), BitmapCreateCacheOption.CacheOnDemand); WicImpl.SetResolution(dpi.X, dpi.Y); - PixelFormat = format; Dpi = dpi; diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WriteableWicBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WriteableWicBitmapImpl.cs index 4c906d62ad..3261c45f15 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WriteableWicBitmapImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WriteableWicBitmapImpl.cs @@ -7,8 +7,8 @@ namespace Avalonia.Direct2D1.Media.Imaging { class WriteableWicBitmapImpl : WicBitmapImpl, IWriteableBitmapImpl { - public WriteableWicBitmapImpl(PixelSize size, Vector dpi, PixelFormat? pixelFormat) - : base(size, dpi, pixelFormat) + public WriteableWicBitmapImpl(PixelSize size, Vector dpi, PixelFormat? pixelFormat, AlphaFormat? alphaFormat) + : base(size, dpi, pixelFormat, alphaFormat) { } diff --git a/src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs b/src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs index 18304ba211..31e9c260e0 100644 --- a/src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs +++ b/src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using Avalonia.Platform; using SharpDX; using SharpDX.Direct2D1; using SharpDX.Mathematics.Interop; @@ -89,14 +90,16 @@ namespace Avalonia.Direct2D1 return CapStyle.Triangle; } - public static Guid ToWic(this Platform.PixelFormat format) + public static Guid ToWic(this Platform.PixelFormat format, Platform.AlphaFormat alphaFormat) { + bool isPremul = alphaFormat == AlphaFormat.Premul; + if (format == Platform.PixelFormat.Rgb565) return SharpDX.WIC.PixelFormat.Format16bppBGR565; if (format == Platform.PixelFormat.Bgra8888) - return SharpDX.WIC.PixelFormat.Format32bppPBGRA; + return isPremul ? SharpDX.WIC.PixelFormat.Format32bppPBGRA : SharpDX.WIC.PixelFormat.Format32bppBGRA; if (format == Platform.PixelFormat.Rgba8888) - return SharpDX.WIC.PixelFormat.Format32bppPRGBA; + return isPremul ? SharpDX.WIC.PixelFormat.Format32bppPRGBA : SharpDX.WIC.PixelFormat.Format32bppRGBA; throw new ArgumentException("Unknown pixel format"); } From 77ef0ea144cb94ae5dc793037757dacf5aea3deb Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Sat, 11 Jul 2020 12:13:47 +0200 Subject: [PATCH 136/344] Fix test. --- src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs | 4 ++-- tests/Avalonia.Benchmarks/NullRenderingPlatform.cs | 4 ++-- tests/Avalonia.RenderTests/Media/BitmapTests.cs | 2 +- tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs | 4 +++- .../VisualTree/MockRenderInterface.cs | 4 ++-- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs b/src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs index f01d335fc7..0a8bb10618 100644 --- a/src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs +++ b/src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs @@ -51,7 +51,7 @@ namespace Avalonia.Headless return new HeadlessBitmapStub(size, dpi); } - public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null) + public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null, AlphaFormat? alphaFormat = null) { return new HeadlessBitmapStub(size, dpi); } @@ -66,7 +66,7 @@ namespace Avalonia.Headless return new HeadlessBitmapStub(new Size(1, 1), new Vector(96, 96)); } - public IBitmapImpl LoadBitmap(PixelFormat format, IntPtr data, PixelSize size, Vector dpi, int stride) + public IBitmapImpl LoadBitmap(PixelFormat format, AlphaFormat alphaFormat, IntPtr data, PixelSize size, Vector dpi, int stride) { return new HeadlessBitmapStub(new Size(1, 1), new Vector(96, 96)); } diff --git a/tests/Avalonia.Benchmarks/NullRenderingPlatform.cs b/tests/Avalonia.Benchmarks/NullRenderingPlatform.cs index d9fb5e03fc..e82ea08970 100644 --- a/tests/Avalonia.Benchmarks/NullRenderingPlatform.cs +++ b/tests/Avalonia.Benchmarks/NullRenderingPlatform.cs @@ -46,7 +46,7 @@ namespace Avalonia.Benchmarks throw new NotImplementedException(); } - public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null) + public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null, AlphaFormat? alphaFormat = null) { throw new NotImplementedException(); } @@ -61,7 +61,7 @@ namespace Avalonia.Benchmarks throw new NotImplementedException(); } - public IBitmapImpl LoadBitmap(PixelFormat format, IntPtr data, PixelSize size, Vector dpi, int stride) + public IBitmapImpl LoadBitmap(PixelFormat format, AlphaFormat alphaFormat, IntPtr data, PixelSize size, Vector dpi, int stride) { throw new NotImplementedException(); } diff --git a/tests/Avalonia.RenderTests/Media/BitmapTests.cs b/tests/Avalonia.RenderTests/Media/BitmapTests.cs index 8773b85045..d52539c371 100644 --- a/tests/Avalonia.RenderTests/Media/BitmapTests.cs +++ b/tests/Avalonia.RenderTests/Media/BitmapTests.cs @@ -81,7 +81,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media ctx.PopOpacity(); } - var bmp = new Bitmap(fmt, fb.Address, fb.Size, new Vector(96, 96), fb.RowBytes); + var bmp = new Bitmap(fmt, AlphaFormat.Premul, fb.Address, fb.Size, new Vector(96, 96), fb.RowBytes); fb.Deallocate(); using (var rtb = new RenderTargetBitmap(new PixelSize(100, 100), new Vector(96, 96))) { diff --git a/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs b/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs index 5f2c6d1a69..c158dfbf64 100644 --- a/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs +++ b/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs @@ -55,7 +55,8 @@ namespace Avalonia.UnitTests public IWriteableBitmapImpl CreateWriteableBitmap( PixelSize size, Vector dpi, - PixelFormat? format = default(PixelFormat?)) + PixelFormat? format = null, + AlphaFormat? alphaFormat = null) { throw new NotImplementedException(); } @@ -87,6 +88,7 @@ namespace Avalonia.UnitTests public IBitmapImpl LoadBitmap( PixelFormat format, + AlphaFormat alphaFormat, IntPtr data, PixelSize size, Vector dpi, diff --git a/tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs b/tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs index 558a9a5968..ca25876ce7 100644 --- a/tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs +++ b/tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs @@ -47,7 +47,7 @@ namespace Avalonia.Visuals.UnitTests.VisualTree throw new NotImplementedException(); } - public IBitmapImpl LoadBitmap(PixelFormat format, IntPtr data, PixelSize size, Vector dpi, int stride) + public IBitmapImpl LoadBitmap(PixelFormat format, AlphaFormat alphaFormat, IntPtr data, PixelSize size, Vector dpi, int stride) { throw new NotImplementedException(); } @@ -64,7 +64,7 @@ namespace Avalonia.Visuals.UnitTests.VisualTree return new MockFontManagerImpl(); } - public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat? fmt) + public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat? fmt, AlphaFormat? alphaFormat) { throw new NotImplementedException(); } From aff78fa6620f369f9a2ddf609a303fa7dbc23994 Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Thu, 30 Jul 2020 23:29:04 +0200 Subject: [PATCH 137/344] Add default alpha and pixel formats to render interfaces. --- .../HeadlessPlatformRenderInterface.cs | 8 +++-- src/Avalonia.Visuals/Media/Imaging/Bitmap.cs | 18 +++++++++++ .../Media/Imaging/WriteableBitmap.cs | 32 ++++++++++++++++--- .../Platform/IPlatformRenderInterface.cs | 16 ++++++++-- .../Avalonia.Skia/PlatformRenderInterface.cs | 8 ++++- src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs | 7 ++-- .../Avalonia.Direct2D1/Direct2D1Platform.cs | 6 +++- .../NullRenderingPlatform.cs | 6 +++- .../MockPlatformRenderInterface.cs | 8 +++-- .../VisualTree/MockRenderInterface.cs | 4 ++- 10 files changed, 94 insertions(+), 19 deletions(-) diff --git a/src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs b/src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs index 0a8bb10618..3ae6c8c30e 100644 --- a/src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs +++ b/src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs @@ -21,7 +21,11 @@ namespace Avalonia.Headless public IEnumerable InstalledFontNames { get; } = new[] { "Tahoma" }; - public bool SupportsIndividualRoundRects => throw new NotImplementedException(); + public bool SupportsIndividualRoundRects => false; + + public AlphaFormat DefaultAlphaFormat => AlphaFormat.Premul; + + public PixelFormat DefaultPixelFormat => PixelFormat.Rgba8888; public IFormattedTextImpl CreateFormattedText(string text, Typeface typeface, double fontSize, TextAlignment textAlignment, TextWrapping wrapping, Size constraint, IReadOnlyList spans) { @@ -51,7 +55,7 @@ namespace Avalonia.Headless return new HeadlessBitmapStub(size, dpi); } - public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null, AlphaFormat? alphaFormat = null) + public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat format, AlphaFormat alphaFormat) { return new HeadlessBitmapStub(size, dpi); } diff --git a/src/Avalonia.Visuals/Media/Imaging/Bitmap.cs b/src/Avalonia.Visuals/Media/Imaging/Bitmap.cs index f86ce326d5..ca303211cd 100644 --- a/src/Avalonia.Visuals/Media/Imaging/Bitmap.cs +++ b/src/Avalonia.Visuals/Media/Imaging/Bitmap.cs @@ -95,6 +95,24 @@ namespace Avalonia.Media.Imaging PlatformImpl.Dispose(); } + /// + /// Initializes a new instance of the class. + /// + /// The pixel format. + /// The alpha format. + /// The pointer to the source bytes. + /// The size of the bitmap in device pixels. + /// The DPI of the bitmap. + /// The number of bytes per row. + [Obsolete("Use overload taking an AlphaFormat.")] + public Bitmap(PixelFormat format, IntPtr data, PixelSize size, Vector dpi, int stride) + { + var ri = AvaloniaLocator.Current.GetService(); + + PlatformImpl = RefCountable.Create(AvaloniaLocator.Current.GetService() + .LoadBitmap(format, ri.DefaultAlphaFormat, data, size, dpi, stride)); + } + /// /// Initializes a new instance of the class. /// diff --git a/src/Avalonia.Visuals/Media/Imaging/WriteableBitmap.cs b/src/Avalonia.Visuals/Media/Imaging/WriteableBitmap.cs index b93706e6e5..b86444bc2f 100644 --- a/src/Avalonia.Visuals/Media/Imaging/WriteableBitmap.cs +++ b/src/Avalonia.Visuals/Media/Imaging/WriteableBitmap.cs @@ -1,4 +1,5 @@ -using Avalonia.Platform; +using System; +using Avalonia.Platform; namespace Avalonia.Media.Imaging { @@ -7,6 +8,19 @@ namespace Avalonia.Media.Imaging /// public class WriteableBitmap : Bitmap { + /// + /// Initializes a new instance of the class. + /// + /// The size of the bitmap in device pixels. + /// The DPI of the bitmap. + /// The pixel format (optional). + /// An . + [Obsolete("Use overload taking an AlphaFormat.")] + public WriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null) + : base(CreatePlatformImpl(size, dpi, format, null)) + { + } + /// /// Initializes a new instance of the class. /// @@ -15,11 +29,21 @@ namespace Avalonia.Media.Imaging /// The pixel format (optional). /// The alpha format (optional). /// An . - public WriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null, AlphaFormat? alphaFormat = null) - : base(AvaloniaLocator.Current.GetService().CreateWriteableBitmap(size, dpi, format, alphaFormat)) + public WriteableBitmap(PixelSize size, Vector dpi, PixelFormat format, AlphaFormat alphaFormat) + : base(CreatePlatformImpl(size, dpi, format, alphaFormat)) { } - + public ILockedFramebuffer Lock() => ((IWriteableBitmapImpl) PlatformImpl.Item).Lock(); + + private static IBitmapImpl CreatePlatformImpl(PixelSize size, in Vector dpi, PixelFormat? format, AlphaFormat? alphaFormat) + { + var ri = AvaloniaLocator.Current.GetService(); + + PixelFormat finalFormat = format ?? ri.DefaultPixelFormat; + AlphaFormat finalAlphaFormat = alphaFormat ?? ri.DefaultAlphaFormat; + + return ri.CreateWriteableBitmap(size, dpi, finalFormat, finalAlphaFormat); + } } } diff --git a/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs b/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs index 5906d4080e..fb4a4427b7 100644 --- a/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs +++ b/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs @@ -81,10 +81,10 @@ namespace Avalonia.Platform ///
/// The size of the bitmap in device pixels. /// The DPI of the bitmap. - /// Pixel format (optional). - /// Alpha format (optional). + /// Pixel format. + /// Alpha format . /// An . - IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null, AlphaFormat? alphaFormat = null); + IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat format, AlphaFormat alphaFormat); /// /// Loads a bitmap implementation from a file.. @@ -141,5 +141,15 @@ namespace Avalonia.Platform IGlyphRunImpl CreateGlyphRun(GlyphRun glyphRun, out double width); bool SupportsIndividualRoundRects { get; } + + /// + /// Default used on this platform. + /// + public AlphaFormat DefaultAlphaFormat { get; } + + /// + /// Default used on this platform. + /// + public PixelFormat DefaultPixelFormat { get; } } } diff --git a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs index 8c53ac2b4e..c4f70df7c0 100644 --- a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs +++ b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs @@ -22,6 +22,8 @@ namespace Avalonia.Skia public PlatformRenderInterface(ISkiaGpu skiaGpu, long? maxResourceBytes = null) { + DefaultPixelFormat = SKImageInfo.PlatformColorType.ToPixelFormat(); + if (skiaGpu != null) { _skiaGpu = skiaGpu; @@ -150,7 +152,7 @@ namespace Avalonia.Skia } /// - public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null, AlphaFormat? alphaFormat = null) + public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat format, AlphaFormat alphaFormat) { return new WriteableBitmapImpl(size, dpi, format, alphaFormat); } @@ -265,5 +267,9 @@ namespace Avalonia.Skia } public bool SupportsIndividualRoundRects => true; + + public AlphaFormat DefaultAlphaFormat => AlphaFormat.Premul; + + public PixelFormat DefaultPixelFormat { get; } } } diff --git a/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs b/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs index 3c29bf65ed..d48e7d10e6 100644 --- a/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs +++ b/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs @@ -23,14 +23,13 @@ namespace Avalonia.Skia /// The DPI of the bitmap. /// The pixel format. /// The alpha format. - public WriteableBitmapImpl(PixelSize size, Vector dpi, PixelFormat? format = null, AlphaFormat? alphaFormat = null) + public WriteableBitmapImpl(PixelSize size, Vector dpi, PixelFormat format, AlphaFormat alphaFormat) { PixelSize = size; Dpi = dpi; - var colorType = PixelFormatHelper.ResolveColorType(format); - - SKAlphaType alphaType = alphaFormat?.ToSkAlphaType() ?? SKAlphaType.Premul; + SKColorType colorType = format.ToSkColorType(); + SKAlphaType alphaType = alphaFormat.ToSkAlphaType(); var runtimePlatform = AvaloniaLocator.Current?.GetService(); diff --git a/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs b/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs index 047cd7a13b..ae927d44a5 100644 --- a/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs +++ b/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs @@ -166,7 +166,7 @@ namespace Avalonia.Direct2D1 return new WicRenderTargetBitmapImpl(size, dpi); } - public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null, AlphaFormat? alphaFormat = null) + public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat format, AlphaFormat alphaFormat) { return new WriteableWicBitmapImpl(size, dpi, format, alphaFormat); } @@ -261,5 +261,9 @@ namespace Avalonia.Direct2D1 } public bool SupportsIndividualRoundRects => false; + + public AlphaFormat DefaultAlphaFormat => AlphaFormat.Premul; + + public PixelFormat DefaultPixelFormat => PixelFormat.Bgra8888; } } diff --git a/tests/Avalonia.Benchmarks/NullRenderingPlatform.cs b/tests/Avalonia.Benchmarks/NullRenderingPlatform.cs index e82ea08970..f632d85c26 100644 --- a/tests/Avalonia.Benchmarks/NullRenderingPlatform.cs +++ b/tests/Avalonia.Benchmarks/NullRenderingPlatform.cs @@ -46,7 +46,7 @@ namespace Avalonia.Benchmarks throw new NotImplementedException(); } - public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null, AlphaFormat? alphaFormat = null) + public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat format, AlphaFormat alphaFormat) { throw new NotImplementedException(); } @@ -94,5 +94,9 @@ namespace Avalonia.Benchmarks } public bool SupportsIndividualRoundRects => true; + + public AlphaFormat DefaultAlphaFormat => AlphaFormat.Premul; + + public PixelFormat DefaultPixelFormat => PixelFormat.Rgba8888; } } diff --git a/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs b/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs index c158dfbf64..08df23cbe1 100644 --- a/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs +++ b/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs @@ -55,8 +55,8 @@ namespace Avalonia.UnitTests public IWriteableBitmapImpl CreateWriteableBitmap( PixelSize size, Vector dpi, - PixelFormat? format = null, - AlphaFormat? alphaFormat = null) + PixelFormat format, + AlphaFormat alphaFormat) { throw new NotImplementedException(); } @@ -104,5 +104,9 @@ namespace Avalonia.UnitTests } public bool SupportsIndividualRoundRects { get; set; } + + public AlphaFormat DefaultAlphaFormat => AlphaFormat.Premul; + + public PixelFormat DefaultPixelFormat => PixelFormat.Rgba8888; } } diff --git a/tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs b/tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs index ca25876ce7..02236e4107 100644 --- a/tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs +++ b/tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs @@ -58,13 +58,15 @@ namespace Avalonia.Visuals.UnitTests.VisualTree } public bool SupportsIndividualRoundRects { get; set; } + public AlphaFormat DefaultAlphaFormat { get; } + public PixelFormat DefaultPixelFormat { get; } public IFontManagerImpl CreateFontManager() { return new MockFontManagerImpl(); } - public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat? fmt, AlphaFormat? alphaFormat) + public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat fmt, AlphaFormat alphaFormat) { throw new NotImplementedException(); } From 776ffbcbdcb6eaa8e32f989a7527bc8a201362dc Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Thu, 30 Jul 2020 23:34:09 +0200 Subject: [PATCH 138/344] Add documentation for alpha format. --- src/Avalonia.Visuals/Platform/AlphaFormat.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Avalonia.Visuals/Platform/AlphaFormat.cs b/src/Avalonia.Visuals/Platform/AlphaFormat.cs index ce8dcde728..3ef8fe9520 100644 --- a/src/Avalonia.Visuals/Platform/AlphaFormat.cs +++ b/src/Avalonia.Visuals/Platform/AlphaFormat.cs @@ -1,9 +1,21 @@ namespace Avalonia.Platform { + /// + /// Describes how to interpret the alpha component of a pixel. + /// public enum AlphaFormat { + /// + /// All pixels have their alpha premultiplied in their color components. + /// Premul, + /// + /// All pixels have their color components stored without any regard to the alpha. e.g. this is the default configuration for PNG images. + /// Unpremul, + /// + /// All pixels are stored as opaque. + /// Opaque } } From 3fc31a0dd5e38d41cded7f83cbc90654cec33af6 Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Thu, 30 Jul 2020 23:37:46 +0200 Subject: [PATCH 139/344] Generate api compat baseline. --- src/Avalonia.Visuals/ApiCompatBaseline.txt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Visuals/ApiCompatBaseline.txt b/src/Avalonia.Visuals/ApiCompatBaseline.txt index 00618448a2..849e957a72 100644 --- a/src/Avalonia.Visuals/ApiCompatBaseline.txt +++ b/src/Avalonia.Visuals/ApiCompatBaseline.txt @@ -1,4 +1,14 @@ Compat issues with assembly Avalonia.Visuals: EnumValuesMustMatch : Enum value 'Avalonia.Media.FontStyle Avalonia.Media.FontStyle.Italic' is (System.Int32)1 in the implementation but (System.Int32)2 in the contract. EnumValuesMustMatch : Enum value 'Avalonia.Media.FontStyle Avalonia.Media.FontStyle.Oblique' is (System.Int32)2 in the implementation but (System.Int32)1 in the contract. -Total Issues: 2 +InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.AlphaFormat Avalonia.Platform.IPlatformRenderInterface.DefaultAlphaFormat' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.PixelFormat Avalonia.Platform.IPlatformRenderInterface.DefaultPixelFormat' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.IWriteableBitmapImpl Avalonia.Platform.IPlatformRenderInterface.CreateWriteableBitmap(Avalonia.PixelSize, Avalonia.Vector, Avalonia.Platform.PixelFormat, Avalonia.Platform.AlphaFormat)' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.IWriteableBitmapImpl Avalonia.Platform.IPlatformRenderInterface.CreateWriteableBitmap(Avalonia.PixelSize, Avalonia.Vector, System.Nullable)' is present in the contract but not in the implementation. +MembersMustExist : Member 'public Avalonia.Platform.IWriteableBitmapImpl Avalonia.Platform.IPlatformRenderInterface.CreateWriteableBitmap(Avalonia.PixelSize, Avalonia.Vector, System.Nullable)' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.AlphaFormat Avalonia.Platform.IPlatformRenderInterface.DefaultAlphaFormat.get()' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.PixelFormat Avalonia.Platform.IPlatformRenderInterface.DefaultPixelFormat.get()' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.IBitmapImpl Avalonia.Platform.IPlatformRenderInterface.LoadBitmap(Avalonia.Platform.PixelFormat, Avalonia.Platform.AlphaFormat, System.IntPtr, Avalonia.PixelSize, Avalonia.Vector, System.Int32)' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.IBitmapImpl Avalonia.Platform.IPlatformRenderInterface.LoadBitmap(Avalonia.Platform.PixelFormat, System.IntPtr, Avalonia.PixelSize, Avalonia.Vector, System.Int32)' is present in the contract but not in the implementation. +MembersMustExist : Member 'public Avalonia.Platform.IBitmapImpl Avalonia.Platform.IPlatformRenderInterface.LoadBitmap(Avalonia.Platform.PixelFormat, System.IntPtr, Avalonia.PixelSize, Avalonia.Vector, System.Int32)' does not exist in the implementation but it does exist in the contract. +Total Issues: 12 From 151ea1b1819cccd6b3f184b72e7d8c8283192e37 Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Thu, 30 Jul 2020 23:59:29 +0200 Subject: [PATCH 140/344] Limit amount of reentrant dispatcher calls. --- .../Threading/AvaloniaScheduler.cs | 61 +++++++++++++++---- 1 file changed, 49 insertions(+), 12 deletions(-) diff --git a/src/Avalonia.Base/Threading/AvaloniaScheduler.cs b/src/Avalonia.Base/Threading/AvaloniaScheduler.cs index 0bfc713ba0..397826df53 100644 --- a/src/Avalonia.Base/Threading/AvaloniaScheduler.cs +++ b/src/Avalonia.Base/Threading/AvaloniaScheduler.cs @@ -9,6 +9,16 @@ namespace Avalonia.Threading /// public class AvaloniaScheduler : LocalScheduler { + /// + /// Users can schedule actions on the dispatcher thread while being on the correct thread already. + /// We are optimizing this case by invoking user callback immediately which can lead to stack overflows in certain cases. + /// To prevent this we are limiting amount of reentrant calls to before we will + /// schedule on a dispatcher anyway. + /// + private const int MaxReentrantSchedules = 32; + + private int _reentrancyGuard; + /// /// The instance of the . /// @@ -24,31 +34,58 @@ namespace Avalonia.Threading /// public override IDisposable Schedule(TState state, TimeSpan dueTime, Func action) { - var composite = new CompositeDisposable(2); + IDisposable PostOnDispatcher() + { + var composite = new CompositeDisposable(2); + + var cancellation = new CancellationDisposable(); + + Dispatcher.UIThread.Post(() => + { + if (!cancellation.Token.IsCancellationRequested) + { + composite.Add(action(this, state)); + } + }, DispatcherPriority.DataBind); + + composite.Add(cancellation); + + return composite; + } + if (dueTime == TimeSpan.Zero) { if (!Dispatcher.UIThread.CheckAccess()) { - var cancellation = new CancellationDisposable(); - Dispatcher.UIThread.Post(() => - { - if (!cancellation.Token.IsCancellationRequested) - { - composite.Add(action(this, state)); - } - }, DispatcherPriority.DataBind); - composite.Add(cancellation); + return PostOnDispatcher(); } else { - return action(this, state); + if (_reentrancyGuard >= MaxReentrantSchedules) + { + return PostOnDispatcher(); + } + + try + { + _reentrancyGuard++; + + return action(this, state); + } + finally + { + _reentrancyGuard--; + } } } else { + var composite = new CompositeDisposable(2); + composite.Add(DispatcherTimer.RunOnce(() => composite.Add(action(this, state)), dueTime)); + + return composite; } - return composite; } } } From b941fd675f7c4f4bd7d382f85dd438f1b260b17d Mon Sep 17 00:00:00 2001 From: Maksym Katsydan Date: Thu, 30 Jul 2020 21:19:33 -0400 Subject: [PATCH 141/344] Default theme: Replace DropDown with ComboBox in ManagedFileChooser --- src/Avalonia.Dialogs/ManagedFileChooser.xaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Dialogs/ManagedFileChooser.xaml b/src/Avalonia.Dialogs/ManagedFileChooser.xaml index ea45e83812..227cc1afc0 100644 --- a/src/Avalonia.Dialogs/ManagedFileChooser.xaml +++ b/src/Avalonia.Dialogs/ManagedFileChooser.xaml @@ -66,7 +66,7 @@ - Date: Thu, 30 Jul 2020 21:42:30 -0400 Subject: [PATCH 142/344] Default theme: Add ToggleSwitch resources --- .../Accents/BaseDark.xaml | 2 + .../Accents/BaseLight.xaml | 2 + src/Avalonia.Themes.Default/TabItem.xaml | 2 +- src/Avalonia.Themes.Default/ToggleSwitch.xaml | 45 ++++++++++++++----- src/Avalonia.Themes.Fluent/ToggleSwitch.xaml | 2 - 5 files changed, 39 insertions(+), 14 deletions(-) diff --git a/src/Avalonia.Themes.Default/Accents/BaseDark.xaml b/src/Avalonia.Themes.Default/Accents/BaseDark.xaml index ffe3e92202..4274f7ee4d 100644 --- a/src/Avalonia.Themes.Default/Accents/BaseDark.xaml +++ b/src/Avalonia.Themes.Default/Accents/BaseDark.xaml @@ -58,6 +58,8 @@ + + 1,1,1,1 0.5 diff --git a/src/Avalonia.Themes.Default/Accents/BaseLight.xaml b/src/Avalonia.Themes.Default/Accents/BaseLight.xaml index c0e5f47eed..b1c0946d0f 100644 --- a/src/Avalonia.Themes.Default/Accents/BaseLight.xaml +++ b/src/Avalonia.Themes.Default/Accents/BaseLight.xaml @@ -61,6 +61,8 @@ + + 1 0.5 diff --git a/src/Avalonia.Themes.Default/TabItem.xaml b/src/Avalonia.Themes.Default/TabItem.xaml index 92482a564c..6e344ce58e 100644 --- a/src/Avalonia.Themes.Default/TabItem.xaml +++ b/src/Avalonia.Themes.Default/TabItem.xaml @@ -2,7 +2,7 @@ - - @@ -262,10 +289,6 @@ - - diff --git a/src/Avalonia.Themes.Fluent/ToggleSwitch.xaml b/src/Avalonia.Themes.Fluent/ToggleSwitch.xaml index 219f6f6742..56249f5986 100644 --- a/src/Avalonia.Themes.Fluent/ToggleSwitch.xaml +++ b/src/Avalonia.Themes.Fluent/ToggleSwitch.xaml @@ -6,8 +6,6 @@ 6 6 154 - 20 - 0 From bf346ff16eb9f52c5529c8f58bb20bca895d9812 Mon Sep 17 00:00:00 2001 From: Maksym Katsydan Date: Thu, 30 Jul 2020 23:10:34 -0400 Subject: [PATCH 143/344] Replace StaticResource with SolidColorBrush+DynamicResource to fix tests --- src/Avalonia.Themes.Default/ToggleSwitch.xaml | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/src/Avalonia.Themes.Default/ToggleSwitch.xaml b/src/Avalonia.Themes.Default/ToggleSwitch.xaml index 48e92d2283..5c0a3b99f3 100644 --- a/src/Avalonia.Themes.Default/ToggleSwitch.xaml +++ b/src/Avalonia.Themes.Default/ToggleSwitch.xaml @@ -8,38 +8,38 @@ 154 0 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 177c6530931449ff500bb103c65d68c8af6d92b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Onak?= Date: Fri, 31 Jul 2020 22:40:11 +0200 Subject: [PATCH 144/344] Revert GridSplitter size for default theme --- src/Avalonia.Themes.Default/GridSplitter.xaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Themes.Default/GridSplitter.xaml b/src/Avalonia.Themes.Default/GridSplitter.xaml index dc5cd002dc..6d9cb4f31f 100644 --- a/src/Avalonia.Themes.Default/GridSplitter.xaml +++ b/src/Avalonia.Themes.Default/GridSplitter.xaml @@ -2,8 +2,8 @@ + + + Test + + + diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index 0a785c3b36..2508915fa4 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -13,6 +13,7 @@ using Avalonia.Metadata; using Avalonia.Data; using Avalonia.Layout; using Avalonia.Utilities; +using Avalonia.Controls.Templates; namespace Avalonia.Controls { @@ -95,11 +96,11 @@ namespace Avalonia.Controls AvaloniaProperty.RegisterDirect(nameof(NewLine), textbox => textbox.NewLine, (textbox, newline) => textbox.NewLine = newline); - public static readonly StyledProperty InnerLeftContentProperty = - AvaloniaProperty.Register(nameof(InnerLeftContent)); + public static readonly StyledProperty InnerLeftContentProperty = + AvaloniaProperty.Register(nameof(InnerLeftContent)); - public static readonly StyledProperty InnerRightContentProperty = - AvaloniaProperty.Register(nameof(InnerRightContent)); + public static readonly StyledProperty InnerRightContentProperty = + AvaloniaProperty.Register(nameof(InnerRightContent)); struct UndoRedoState : IEquatable { @@ -332,13 +333,13 @@ namespace Avalonia.Controls set { SetValue(UseFloatingWatermarkProperty, value); } } - public object InnerLeftContent + public IControlTemplate InnerLeftContent { get { return GetValue(InnerLeftContentProperty); } set { SetValue(InnerLeftContentProperty, value); } } - public object InnerRightContent + public IControlTemplate InnerRightContent { get { return GetValue(InnerRightContentProperty); } set { SetValue(InnerRightContentProperty, value); } diff --git a/src/Avalonia.Themes.Fluent/TextBox.xaml b/src/Avalonia.Themes.Fluent/TextBox.xaml index 847248bafa..99d8d613eb 100644 --- a/src/Avalonia.Themes.Fluent/TextBox.xaml +++ b/src/Avalonia.Themes.Fluent/TextBox.xaml @@ -38,14 +38,14 @@ - - + + - + From 88a63dde2c4d68cef09cbd8c0b131445e57133f6 Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Sat, 1 Aug 2020 09:03:30 +0800 Subject: [PATCH 147/344] use contentpresenter --- samples/ControlCatalog/Pages/TextBoxPage.xaml | 4 +- src/Avalonia.Controls/TextBox.cs | 13 ++-- src/Avalonia.Themes.Fluent/TextBox.xaml | 73 +++++++++++++++---- 3 files changed, 65 insertions(+), 25 deletions(-) diff --git a/samples/ControlCatalog/Pages/TextBoxPage.xaml b/samples/ControlCatalog/Pages/TextBoxPage.xaml index cc0e86b904..83378963e8 100644 --- a/samples/ControlCatalog/Pages/TextBoxPage.xaml +++ b/samples/ControlCatalog/Pages/TextBoxPage.xaml @@ -44,9 +44,9 @@ diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index 2508915fa4..0a785c3b36 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -13,7 +13,6 @@ using Avalonia.Metadata; using Avalonia.Data; using Avalonia.Layout; using Avalonia.Utilities; -using Avalonia.Controls.Templates; namespace Avalonia.Controls { @@ -96,11 +95,11 @@ namespace Avalonia.Controls AvaloniaProperty.RegisterDirect(nameof(NewLine), textbox => textbox.NewLine, (textbox, newline) => textbox.NewLine = newline); - public static readonly StyledProperty InnerLeftContentProperty = - AvaloniaProperty.Register(nameof(InnerLeftContent)); + public static readonly StyledProperty InnerLeftContentProperty = + AvaloniaProperty.Register(nameof(InnerLeftContent)); - public static readonly StyledProperty InnerRightContentProperty = - AvaloniaProperty.Register(nameof(InnerRightContent)); + public static readonly StyledProperty InnerRightContentProperty = + AvaloniaProperty.Register(nameof(InnerRightContent)); struct UndoRedoState : IEquatable { @@ -333,13 +332,13 @@ namespace Avalonia.Controls set { SetValue(UseFloatingWatermarkProperty, value); } } - public IControlTemplate InnerLeftContent + public object InnerLeftContent { get { return GetValue(InnerLeftContentProperty); } set { SetValue(InnerLeftContentProperty, value); } } - public IControlTemplate InnerRightContent + public object InnerRightContent { get { return GetValue(InnerRightContentProperty); } set { SetValue(InnerRightContentProperty, value); } diff --git a/src/Avalonia.Themes.Fluent/TextBox.xaml b/src/Avalonia.Themes.Fluent/TextBox.xaml index 99d8d613eb..ec232b33ae 100644 --- a/src/Avalonia.Themes.Fluent/TextBox.xaml +++ b/src/Avalonia.Themes.Fluent/TextBox.xaml @@ -1,5 +1,4 @@ - + 0,0,0,4 @@ -9,7 +8,7 @@ - + @@ -19,33 +18,75 @@ - + - + - + - + - - - - + + + + - + - + - + - + - + From 13ad0bf9a2d73c6bdd97e78b1aea72ea530064f0 Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Sat, 1 Aug 2020 09:04:50 +0800 Subject: [PATCH 148/344] move it up --- samples/ControlCatalog/Pages/TextBoxPage.xaml | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/samples/ControlCatalog/Pages/TextBoxPage.xaml b/samples/ControlCatalog/Pages/TextBoxPage.xaml index 83378963e8..795e675f70 100644 --- a/samples/ControlCatalog/Pages/TextBoxPage.xaml +++ b/samples/ControlCatalog/Pages/TextBoxPage.xaml @@ -1,6 +1,23 @@ + + + + + + + Test + + + TextBox A control into which the user can input text @@ -40,21 +57,6 @@ - - - - - - Test - - From 06d93f32161011d6b57466b66d7e8bbc9996dff7 Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Sat, 1 Aug 2020 09:06:45 +0800 Subject: [PATCH 149/344] test --- samples/ControlCatalog/Pages/TextBoxPage.xaml | 4 ++-- src/Avalonia.Themes.Fluent/TextBox.xaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/ControlCatalog/Pages/TextBoxPage.xaml b/samples/ControlCatalog/Pages/TextBoxPage.xaml index 795e675f70..093e3087e5 100644 --- a/samples/ControlCatalog/Pages/TextBoxPage.xaml +++ b/samples/ControlCatalog/Pages/TextBoxPage.xaml @@ -6,9 +6,9 @@ diff --git a/src/Avalonia.Themes.Fluent/TextBox.xaml b/src/Avalonia.Themes.Fluent/TextBox.xaml index ec232b33ae..4e96751bc6 100644 --- a/src/Avalonia.Themes.Fluent/TextBox.xaml +++ b/src/Avalonia.Themes.Fluent/TextBox.xaml @@ -86,7 +86,7 @@ HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/> - + From ad78086d0a091b184cde7abc279b532791f26a5f Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Sat, 1 Aug 2020 09:22:00 +0800 Subject: [PATCH 150/344] fix padding --- src/Avalonia.Themes.Fluent/TextBox.xaml | 85 +++++++++++++------------ 1 file changed, 43 insertions(+), 42 deletions(-) diff --git a/src/Avalonia.Themes.Fluent/TextBox.xaml b/src/Avalonia.Themes.Fluent/TextBox.xaml index 4e96751bc6..5278e5d3d0 100644 --- a/src/Avalonia.Themes.Fluent/TextBox.xaml +++ b/src/Avalonia.Themes.Fluent/TextBox.xaml @@ -37,31 +37,30 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + Margin="0 1 0 0" + Text="{TemplateBinding Text, Mode=TwoWay}" + CaretIndex="{TemplateBinding CaretIndex}" + SelectionStart="{TemplateBinding SelectionStart}" + SelectionEnd="{TemplateBinding SelectionEnd}" + TextAlignment="{TemplateBinding TextAlignment}" + TextWrapping="{TemplateBinding TextWrapping}" + PasswordChar="{TemplateBinding PasswordChar}" + SelectionBrush="{TemplateBinding SelectionBrush}" + SelectionForegroundBrush="{TemplateBinding SelectionForegroundBrush}" + CaretBrush="{TemplateBinding CaretBrush}" + HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" + VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/> - - - - - + + + + + + + From 9ca05ec23dc6cf15e2518e807f242c8cd5a8e3af Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Sat, 1 Aug 2020 09:25:41 +0800 Subject: [PATCH 151/344] update textboxpage --- samples/ControlCatalog/Pages/TextBoxPage.xaml | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/samples/ControlCatalog/Pages/TextBoxPage.xaml b/samples/ControlCatalog/Pages/TextBoxPage.xaml index 093e3087e5..348a285f44 100644 --- a/samples/ControlCatalog/Pages/TextBoxPage.xaml +++ b/samples/ControlCatalog/Pages/TextBoxPage.xaml @@ -2,21 +2,24 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="ControlCatalog.Pages.TextBoxPage"> - - - - - - Test - - + + + + TextBox A control into which the user can input text @@ -39,6 +42,8 @@ + + resm fonts From 32a34117e75f735245797390a2308987b9aceab3 Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Sat, 1 Aug 2020 10:19:06 +0800 Subject: [PATCH 152/344] prototype --- samples/ControlCatalog/Pages/TextBoxPage.xaml | 20 ++++++++----- src/Avalonia.Controls/TextBox.cs | 28 +++++++++++++++++-- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/samples/ControlCatalog/Pages/TextBoxPage.xaml b/samples/ControlCatalog/Pages/TextBoxPage.xaml index 348a285f44..d6fc234f17 100644 --- a/samples/ControlCatalog/Pages/TextBoxPage.xaml +++ b/samples/ControlCatalog/Pages/TextBoxPage.xaml @@ -4,21 +4,26 @@ + + TextBox @@ -31,7 +36,8 @@ - + + @@ -42,8 +48,8 @@ - - + + resm fonts diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index 0a785c3b36..23728d7997 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -101,6 +101,9 @@ namespace Avalonia.Controls public static readonly StyledProperty InnerRightContentProperty = AvaloniaProperty.Register(nameof(InnerRightContent)); + public static readonly StyledProperty ShowPasswordProperty = + AvaloniaProperty.Register(nameof(ShowPassword)); + struct UndoRedoState : IEquatable { public string Text { get; } @@ -129,6 +132,10 @@ namespace Avalonia.Controls static TextBox() { FocusableProperty.OverrideDefaultValue(typeof(TextBox), true); + ShowPasswordProperty.Changed.Subscribe((x)=> + { + + }); } public TextBox() @@ -291,7 +298,7 @@ namespace Avalonia.Controls else { HandleTextInput(value); - } + } _undoRedoHelper.Snapshot(); } } @@ -344,6 +351,16 @@ namespace Avalonia.Controls set { SetValue(InnerRightContentProperty, value); } } + public bool ShowPassword + { + get { return GetValue(ShowPasswordProperty); } + set + { + + SetValue(ShowPasswordProperty, value); + } + } + public TextWrapping TextWrapping { get { return GetValue(TextWrappingProperty); } @@ -774,7 +791,7 @@ namespace Avalonia.Controls // if it did not, we change the selection to where the user clicked var firstSelection = Math.Min(SelectionStart, SelectionEnd); var lastSelection = Math.Max(SelectionStart, SelectionEnd); - var didClickInSelection = SelectionStart != SelectionEnd && + var didClickInSelection = SelectionStart != SelectionEnd && caretIndex >= firstSelection && caretIndex <= lastSelection; if (!didClickInSelection) { @@ -821,6 +838,11 @@ namespace Avalonia.Controls } } + public void Clear() + { + Text = string.Empty; + } + private int DeleteCharacter(int index) { var start = index + 1; @@ -1086,7 +1108,7 @@ namespace Avalonia.Controls SelectionEnd = CaretIndex; } - private bool IsPasswordBox => PasswordChar != default(char); + private bool IsPasswordBox => ShowPassword && PasswordChar != default(char); UndoRedoState UndoRedoHelper.IUndoRedoHost.UndoRedoState { From 376ee843caf68bc986627b75b175b4a57e6fbdd5 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Sat, 1 Aug 2020 13:55:15 +0300 Subject: [PATCH 153/344] Fixed concurrency issues in RenderLoop --- src/Avalonia.Visuals/Rendering/RenderLoop.cs | 40 ++++++++++++++------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/src/Avalonia.Visuals/Rendering/RenderLoop.cs b/src/Avalonia.Visuals/Rendering/RenderLoop.cs index 789d028a3a..26011e4b92 100644 --- a/src/Avalonia.Visuals/Rendering/RenderLoop.cs +++ b/src/Avalonia.Visuals/Rendering/RenderLoop.cs @@ -18,6 +18,7 @@ namespace Avalonia.Rendering { private readonly IDispatcher _dispatcher; private List _items = new List(); + private List _itemsCopy = new List(); private IRenderTimer _timer; private int _inTick; private int _inUpdate; @@ -63,11 +64,14 @@ namespace Avalonia.Rendering Contract.Requires(i != null); Dispatcher.UIThread.VerifyAccess(); - _items.Add(i); - - if (_items.Count == 1) + lock (_items) { - Timer.Tick += TimerTick; + _items.Add(i); + + if (_items.Count == 1) + { + Timer.Tick += TimerTick; + } } } @@ -76,15 +80,17 @@ namespace Avalonia.Rendering { Contract.Requires(i != null); Dispatcher.UIThread.VerifyAccess(); - - _items.Remove(i); - - if (_items.Count == 0) + lock (_items) { - Timer.Tick -= TimerTick; + _items.Remove(i); + + if (_items.Count == 0) + { + Timer.Tick -= TimerTick; + } } } - + private void TimerTick(TimeSpan time) { if (Interlocked.CompareExchange(ref _inTick, 1, 0) == 0) @@ -129,10 +135,20 @@ namespace Avalonia.Rendering }, DispatcherPriority.Render); } - for(int i = 0; i < _items.Count; i++) + lock (_items) { - _items[i].Render(); + _itemsCopy.Clear(); + foreach (var i in _items) + _itemsCopy.Add(i); } + + for (int i = 0; i < _itemsCopy.Count; i++) + { + _itemsCopy[i].Render(); + } + + _itemsCopy.Clear(); + } catch (Exception ex) { From 475fea4d1d2ae82003cc20e13902081ce8560fd9 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Sat, 1 Aug 2020 14:04:08 +0300 Subject: [PATCH 154/344] Added SleepLoopRenderTimer because of libnvidia-glcore.so crashes --- .../Rendering/SleepLoopRenderTimer.cs | 33 +++++++++++++++++++ src/Avalonia.X11/X11Platform.cs | 2 +- 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 src/Avalonia.Visuals/Rendering/SleepLoopRenderTimer.cs diff --git a/src/Avalonia.Visuals/Rendering/SleepLoopRenderTimer.cs b/src/Avalonia.Visuals/Rendering/SleepLoopRenderTimer.cs new file mode 100644 index 0000000000..a44891a888 --- /dev/null +++ b/src/Avalonia.Visuals/Rendering/SleepLoopRenderTimer.cs @@ -0,0 +1,33 @@ +using System; +using System.Diagnostics; +using System.Threading; + +namespace Avalonia.Rendering +{ + public class SleepLoopRenderTimer : IRenderTimer + { + public event Action Tick; + + public SleepLoopRenderTimer(int fps) + { + var timeBetweenTicks = TimeSpan.FromSeconds(1d / fps); + new Thread(() => + { + var st = Stopwatch.StartNew(); + var now = st.Elapsed; + var lastTick = now; + + while (true) + { + var timeTillNextTick = lastTick + timeBetweenTicks - now; + if (timeTillNextTick.TotalMilliseconds > 1) + Thread.Sleep(timeTillNextTick); + + + Tick?.Invoke(now); + now = st.Elapsed; + } + }) { IsBackground = true }.Start(); + } + } +} diff --git a/src/Avalonia.X11/X11Platform.cs b/src/Avalonia.X11/X11Platform.cs index 9e9c4fd30e..7f3255d4da 100644 --- a/src/Avalonia.X11/X11Platform.cs +++ b/src/Avalonia.X11/X11Platform.cs @@ -47,7 +47,7 @@ namespace Avalonia.X11 AvaloniaLocator.CurrentMutable.BindToSelf(this) .Bind().ToConstant(this) .Bind().ToConstant(new X11PlatformThreading(this)) - .Bind().ToConstant(new DefaultRenderTimer(60)) + .Bind().ToConstant(new SleepLoopRenderTimer(60)) .Bind().ToConstant(new RenderLoop()) .Bind().ToConstant(new PlatformHotkeyConfiguration(KeyModifiers.Control)) .Bind().ToFunc(() => KeyboardDevice) From 90aad3b785f4854e768922491bd7ad849fa82a18 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Sat, 1 Aug 2020 14:25:50 +0300 Subject: [PATCH 155/344] Stop the loop when there are no subscribers --- .../Rendering/SleepLoopRenderTimer.cs | 65 +++++++++++++++---- 1 file changed, 52 insertions(+), 13 deletions(-) diff --git a/src/Avalonia.Visuals/Rendering/SleepLoopRenderTimer.cs b/src/Avalonia.Visuals/Rendering/SleepLoopRenderTimer.cs index a44891a888..79e029ccd2 100644 --- a/src/Avalonia.Visuals/Rendering/SleepLoopRenderTimer.cs +++ b/src/Avalonia.Visuals/Rendering/SleepLoopRenderTimer.cs @@ -6,28 +6,67 @@ namespace Avalonia.Rendering { public class SleepLoopRenderTimer : IRenderTimer { - public event Action Tick; + private Action _tick; + private int _count; + private readonly object _lock = new object(); + private bool _running; + private readonly Stopwatch _st = Stopwatch.StartNew(); + private readonly TimeSpan _timeBetweenTicks; public SleepLoopRenderTimer(int fps) { - var timeBetweenTicks = TimeSpan.FromSeconds(1d / fps); - new Thread(() => + _timeBetweenTicks = TimeSpan.FromSeconds(1d / fps); + } + + public event Action Tick + { + add { - var st = Stopwatch.StartNew(); - var now = st.Elapsed; - var lastTick = now; + lock (_lock) + { + _tick += value; + _count++; + if (_running) + return; + _running = true; + new Thread(LoopProc) { IsBackground = true }.Start(); + } - while (true) + } + remove + { + lock (_lock) { - var timeTillNextTick = lastTick + timeBetweenTicks - now; - if (timeTillNextTick.TotalMilliseconds > 1) - Thread.Sleep(timeTillNextTick); + _tick -= value; + _count--; + } + } + } + void LoopProc() + { + var now = _st.Elapsed; + var lastTick = now; + + while (true) + { + var timeTillNextTick = lastTick + _timeBetweenTicks - now; + if (timeTillNextTick.TotalMilliseconds > 1) Thread.Sleep(timeTillNextTick); - Tick?.Invoke(now); - now = st.Elapsed; + lock (_lock) + { + if (_count == 0) + { + _running = false; + return; + } } - }) { IsBackground = true }.Start(); + + _tick?.Invoke(now); + now = _st.Elapsed; + } } + + } } From a899f4040e22c333ddbbc2135566288fea047f4e Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sat, 1 Aug 2020 10:26:38 -0300 Subject: [PATCH 156/344] use two way binding. --- samples/ControlCatalog/Pages/TextBoxPage.xaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/ControlCatalog/Pages/TextBoxPage.xaml b/samples/ControlCatalog/Pages/TextBoxPage.xaml index d6fc234f17..cae3d20169 100644 --- a/samples/ControlCatalog/Pages/TextBoxPage.xaml +++ b/samples/ControlCatalog/Pages/TextBoxPage.xaml @@ -20,7 +20,7 @@ From 52d961deed3bff55c46f2d670f26a4ba87068bd2 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sat, 1 Aug 2020 11:42:04 -0300 Subject: [PATCH 157/344] remove whitespace. --- src/Avalonia.Visuals/Rendering/RenderLoop.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Visuals/Rendering/RenderLoop.cs b/src/Avalonia.Visuals/Rendering/RenderLoop.cs index 26011e4b92..b2a6b0da19 100644 --- a/src/Avalonia.Visuals/Rendering/RenderLoop.cs +++ b/src/Avalonia.Visuals/Rendering/RenderLoop.cs @@ -90,7 +90,7 @@ namespace Avalonia.Rendering } } } - + private void TimerTick(TimeSpan time) { if (Interlocked.CompareExchange(ref _inTick, 1, 0) == 0) From 01bb6ec93694fcf80b528d493e109b6eddacd721 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 3 Aug 2020 14:26:48 +0200 Subject: [PATCH 158/344] Added API compat changes. --- src/Avalonia.Controls/ApiCompatBaseline.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/Avalonia.Controls/ApiCompatBaseline.txt diff --git a/src/Avalonia.Controls/ApiCompatBaseline.txt b/src/Avalonia.Controls/ApiCompatBaseline.txt new file mode 100644 index 0000000000..0a2415a263 --- /dev/null +++ b/src/Avalonia.Controls/ApiCompatBaseline.txt @@ -0,0 +1,7 @@ +Compat issues with assembly Avalonia.Controls: +MembersMustExist : Member 'protected void Avalonia.Controls.ComboBox.PopupClosedOverride(Avalonia.Controls.Primitives.PopupClosedEventArgs)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public Avalonia.StyledProperty Avalonia.StyledProperty Avalonia.Controls.Primitives.Popup.StaysOpenProperty' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public void Avalonia.Controls.Primitives.Popup.add_Closed(System.EventHandler)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public void Avalonia.Controls.Primitives.Popup.remove_Closed(System.EventHandler)' does not exist in the implementation but it does exist in the contract. +TypesMustExist : Type 'Avalonia.Controls.Primitives.PopupClosedEventArgs' does not exist in the implementation but it does exist in the contract. +Total Issues: 5 From db648cc6f85e5a16127d0da74a85c7b2b2c6db61 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 3 Aug 2020 14:32:40 +0200 Subject: [PATCH 159/344] Set OverlayInputPassThroughElement in MenuItem template. --- src/Avalonia.Controls/Menu.cs | 14 -------------- src/Avalonia.Themes.Fluent/MenuItem.xaml | 3 ++- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/src/Avalonia.Controls/Menu.cs b/src/Avalonia.Controls/Menu.cs index f74daa791d..4da044fec1 100644 --- a/src/Avalonia.Controls/Menu.cs +++ b/src/Avalonia.Controls/Menu.cs @@ -48,13 +48,6 @@ namespace Avalonia.Controls return; } - if (_overlay?.InputPassThroughElement == this) - { - _overlay.InputPassThroughElement = null; - } - - _overlay = null; - foreach (var i in ((IMenu)this).SubItems) { i.Close(); @@ -78,13 +71,6 @@ namespace Avalonia.Controls return; } - _overlay = LightDismissOverlayLayer.GetLightDismissOverlayLayer(this); - - if (_overlay is object) - { - _overlay.InputPassThroughElement = this; - } - IsOpen = true; RaiseEvent(new RoutedEventArgs diff --git a/src/Avalonia.Themes.Fluent/MenuItem.xaml b/src/Avalonia.Themes.Fluent/MenuItem.xaml index 4335650aef..746a315ce0 100644 --- a/src/Avalonia.Themes.Fluent/MenuItem.xaml +++ b/src/Avalonia.Themes.Fluent/MenuItem.xaml @@ -161,7 +161,8 @@ WindowManagerAddShadowHint="False" MinWidth="{Binding Bounds.Width, RelativeSource={RelativeSource TemplatedParent}}" IsLightDismissEnabled="True" - IsOpen="{TemplateBinding IsSubMenuOpen, Mode=TwoWay}"> + IsOpen="{TemplateBinding IsSubMenuOpen, Mode=TwoWay}" + OverlayInputPassThroughElement="{Binding $parent[Menu]}"> Date: Mon, 3 Aug 2020 15:29:45 +0200 Subject: [PATCH 160/344] Remove outdated submodule. --- src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github | 1 - 1 file changed, 1 deletion(-) delete mode 160000 src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github b/src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github deleted file mode 160000 index 7d15a92274..0000000000 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7d15a9227461cf4d62bc2ed251fcc25c96b28aaf From 5947d9ad6ba6473ab36d63dd37f1e26be7584559 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 3 Aug 2020 15:46:26 +0200 Subject: [PATCH 161/344] Capture mouse when passing through event. This moves the implicit capture from the overlay layer to the target element. --- src/Avalonia.Controls/Primitives/Popup.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs index 71efd322ec..a676892384 100644 --- a/src/Avalonia.Controls/Primitives/Popup.cs +++ b/src/Avalonia.Controls/Primitives/Popup.cs @@ -606,6 +606,7 @@ namespace Avalonia.Controls.Primitives if (hit != null) { + e.Pointer.Capture(hit); hit.RaiseEvent(e); e.Handled = true; } From 836203d0337899aacc257eee755b8094aa39fc2d Mon Sep 17 00:00:00 2001 From: amwx Date: Mon, 3 Aug 2020 15:58:34 -0500 Subject: [PATCH 162/344] Fix ArgumentOutOfRange exception --- .../DateTimePickers/DatePickerPresenter.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs b/src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs index 31527ccb16..eec4615736 100644 --- a/src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs +++ b/src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs @@ -356,10 +356,17 @@ namespace Avalonia.Controls } if (MonthVisible) + { _monthSelector.SelectedValue = dt.Month; - + _monthSelector.FormatDate = dt.Date; + } + if (YearVisible) + { _yearSelector.SelectedValue = dt.Year; + _yearSelector.FormatDate = dt.Date; + } + _suppressUpdateSelection = false; SetInitialFocus(); From 802b459275867c3642f05c6a59c4afd666043aa3 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 3 Aug 2020 23:09:07 +0200 Subject: [PATCH 163/344] Fix DesignWidth/DesignHeight. Ensure that design mode properties are set before setting `SizeToContent`. --- src/Avalonia.DesignerSupport/DesignWindowLoader.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.DesignerSupport/DesignWindowLoader.cs b/src/Avalonia.DesignerSupport/DesignWindowLoader.cs index 59862da230..b009778f97 100644 --- a/src/Avalonia.DesignerSupport/DesignWindowLoader.cs +++ b/src/Avalonia.DesignerSupport/DesignWindowLoader.cs @@ -69,6 +69,8 @@ namespace Avalonia.DesignerSupport window = new Window() {Content = (Control)control}; } + Design.ApplyDesignModeProperties(window, control); + if (!window.IsSet(Window.SizeToContentProperty)) { if (double.IsNaN(window.Width)) @@ -83,7 +85,6 @@ namespace Avalonia.DesignerSupport } } window.Show(); - Design.ApplyDesignModeProperties(window, control); return window; } } From 2f39eb16e0d97855be6d80f833478a46dec90e19 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Tue, 4 Aug 2020 13:10:44 +0200 Subject: [PATCH 164/344] Stop ItemsSourceView using a cached size. It can mean that `Count` is out-of-date with regards to the inner collection if it's accessed in a collection changed handler before `OnItemsSourceChanged` is fired. It's never been clear to me why ItemsSourceView caches the size; I suspect it's due to the performance characteristics of WinRT and so I think it can be safely removed in Avalonia. Fixes #4409 --- src/Avalonia.Controls/Repeater/ItemsSourceView.cs | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/Avalonia.Controls/Repeater/ItemsSourceView.cs b/src/Avalonia.Controls/Repeater/ItemsSourceView.cs index ecf8abc13f..def9301e2d 100644 --- a/src/Avalonia.Controls/Repeater/ItemsSourceView.cs +++ b/src/Avalonia.Controls/Repeater/ItemsSourceView.cs @@ -25,7 +25,6 @@ namespace Avalonia.Controls { private readonly IList _inner; private INotifyCollectionChanged _notifyCollectionChanged; - private int _cachedSize = -1; /// /// Initializes a new instance of the ItemsSourceView class for the specified data source. @@ -54,18 +53,7 @@ namespace Avalonia.Controls /// /// Gets the number of items in the collection. /// - public int Count - { - get - { - if (_cachedSize == -1) - { - _cachedSize = _inner.Count; - } - - return _cachedSize; - } - } + public int Count => _inner.Count; /// /// Gets a value that indicates whether the items source can provide a unique key for each item. @@ -126,7 +114,6 @@ namespace Avalonia.Controls protected void OnItemsSourceChanged(NotifyCollectionChangedEventArgs args) { - _cachedSize = _inner.Count; CollectionChanged?.Invoke(this, args); } From d242e1b5dddc2654019c8c493bb4aa9b80a360fe Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Tue, 4 Aug 2020 16:20:17 +0200 Subject: [PATCH 165/344] Revert "Fix shared size group for fluent sub menu" This reverts commit 85c09761ba8dbb52bafa9d5486801ad7223b70cb. --- src/Avalonia.Controls/MenuItem.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/MenuItem.cs b/src/Avalonia.Controls/MenuItem.cs index 789e4f8926..912abc6de3 100644 --- a/src/Avalonia.Controls/MenuItem.cs +++ b/src/Avalonia.Controls/MenuItem.cs @@ -97,6 +97,7 @@ namespace Avalonia.Controls private ICommand _command; private bool _commandCanExecute = true; private Popup _popup; + private IDisposable _gridHack; /// /// Initializes static members of the class. @@ -322,6 +323,9 @@ namespace Avalonia.Controls { Command.CanExecuteChanged -= CanExecuteChanged; } + + _gridHack?.Dispose(); + _gridHack = null; } protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) @@ -341,7 +345,9 @@ namespace Avalonia.Controls // the WPF codebase: // // https://github.com/dotnet/wpf/blob/89537909bdf36bc918e88b37751add46a8980bb0/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/MenuItem.cs#L2126-L2141 - SetValue(DefinitionBase.PrivateSharedSizeScopeProperty, parent.GetValue(DefinitionBase.PrivateSharedSizeScopeProperty)); + _gridHack = Bind( + DefinitionBase.PrivateSharedSizeScopeProperty, + parent.GetBindingObservable(DefinitionBase.PrivateSharedSizeScopeProperty)); } } From ce0721deb641537cbcbe65c2c89603b19ee2379f Mon Sep 17 00:00:00 2001 From: amwx Date: Tue, 4 Aug 2020 23:03:03 -0500 Subject: [PATCH 166/344] Add Default Theme Support --- .../Accents/BaseDark.xaml | 3 + .../Accents/BaseLight.xaml | 3 + src/Avalonia.Themes.Default/DatePicker.xaml | 334 ++++++++++++++++++ src/Avalonia.Themes.Default/DefaultTheme.xaml | 3 + src/Avalonia.Themes.Default/SplitView.xaml | 219 ++++++++++++ src/Avalonia.Themes.Default/TimePicker.xaml | 283 +++++++++++++++ 6 files changed, 845 insertions(+) create mode 100644 src/Avalonia.Themes.Default/DatePicker.xaml create mode 100644 src/Avalonia.Themes.Default/SplitView.xaml create mode 100644 src/Avalonia.Themes.Default/TimePicker.xaml diff --git a/src/Avalonia.Themes.Default/Accents/BaseDark.xaml b/src/Avalonia.Themes.Default/Accents/BaseDark.xaml index 4274f7ee4d..44dfb9ea48 100644 --- a/src/Avalonia.Themes.Default/Accents/BaseDark.xaml +++ b/src/Avalonia.Themes.Default/Accents/BaseDark.xaml @@ -58,6 +58,9 @@ + + + 1,1,1,1 diff --git a/src/Avalonia.Themes.Default/Accents/BaseLight.xaml b/src/Avalonia.Themes.Default/Accents/BaseLight.xaml index b1c0946d0f..9ed3207235 100644 --- a/src/Avalonia.Themes.Default/Accents/BaseLight.xaml +++ b/src/Avalonia.Themes.Default/Accents/BaseLight.xaml @@ -61,6 +61,9 @@ + + + 1 diff --git a/src/Avalonia.Themes.Default/DatePicker.xaml b/src/Avalonia.Themes.Default/DatePicker.xaml new file mode 100644 index 0000000000..da878c88e2 --- /dev/null +++ b/src/Avalonia.Themes.Default/DatePicker.xaml @@ -0,0 +1,334 @@ + + + + + 0,0,0,4 + 40 + 40 + 41 + 296 + 456 + 0,3,0,6 + 9,3,0,6 + 0,3,0,6 + 9,3,0,6 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Default/DefaultTheme.xaml b/src/Avalonia.Themes.Default/DefaultTheme.xaml index 4e63d1d223..e5b654b490 100644 --- a/src/Avalonia.Themes.Default/DefaultTheme.xaml +++ b/src/Avalonia.Themes.Default/DefaultTheme.xaml @@ -55,4 +55,7 @@ + + + diff --git a/src/Avalonia.Themes.Default/SplitView.xaml b/src/Avalonia.Themes.Default/SplitView.xaml new file mode 100644 index 0000000000..4a9a7be164 --- /dev/null +++ b/src/Avalonia.Themes.Default/SplitView.xaml @@ -0,0 +1,219 @@ + + + + 320 + 48 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Default/TimePicker.xaml b/src/Avalonia.Themes.Default/TimePicker.xaml new file mode 100644 index 0000000000..6c4d0c97bd --- /dev/null +++ b/src/Avalonia.Themes.Default/TimePicker.xaml @@ -0,0 +1,283 @@ + + + + + 40 + 1 + 1 + 0,0,0,4 + 40 + 41 + 242 + 456 + 0,3,0,6 + 0,3,0,6 + + + + + + + + + + + + + + + + + + + + + + + + + + From 96d1d7358192511886a8e33ea54df17485ce7309 Mon Sep 17 00:00:00 2001 From: amwx Date: Tue, 4 Aug 2020 23:14:28 -0500 Subject: [PATCH 167/344] SplitView Default style --- src/Avalonia.Themes.Default/SplitView.xaml | 219 +++++++++++++++++++++ 1 file changed, 219 insertions(+) create mode 100644 src/Avalonia.Themes.Default/SplitView.xaml diff --git a/src/Avalonia.Themes.Default/SplitView.xaml b/src/Avalonia.Themes.Default/SplitView.xaml new file mode 100644 index 0000000000..4a9a7be164 --- /dev/null +++ b/src/Avalonia.Themes.Default/SplitView.xaml @@ -0,0 +1,219 @@ + + + + 320 + 48 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 80863f44a9d38731f15c8bb4551d54c153c2b5ca Mon Sep 17 00:00:00 2001 From: amwx Date: Tue, 4 Aug 2020 23:15:01 -0500 Subject: [PATCH 168/344] Date/Time Picker default style --- src/Avalonia.Themes.Default/DatePicker.xaml | 334 ++++++++++++++++++++ src/Avalonia.Themes.Default/TimePicker.xaml | 283 +++++++++++++++++ 2 files changed, 617 insertions(+) create mode 100644 src/Avalonia.Themes.Default/DatePicker.xaml create mode 100644 src/Avalonia.Themes.Default/TimePicker.xaml diff --git a/src/Avalonia.Themes.Default/DatePicker.xaml b/src/Avalonia.Themes.Default/DatePicker.xaml new file mode 100644 index 0000000000..da878c88e2 --- /dev/null +++ b/src/Avalonia.Themes.Default/DatePicker.xaml @@ -0,0 +1,334 @@ + + + + + 0,0,0,4 + 40 + 40 + 41 + 296 + 456 + 0,3,0,6 + 9,3,0,6 + 0,3,0,6 + 9,3,0,6 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Default/TimePicker.xaml b/src/Avalonia.Themes.Default/TimePicker.xaml new file mode 100644 index 0000000000..6c4d0c97bd --- /dev/null +++ b/src/Avalonia.Themes.Default/TimePicker.xaml @@ -0,0 +1,283 @@ + + + + + 40 + 1 + 1 + 0,0,0,4 + 40 + 41 + 242 + 456 + 0,3,0,6 + 0,3,0,6 + + + + + + + + + + + + + + + + + + + + + + + + + + From 7ef5078610930498485f7d578d816418ad838734 Mon Sep 17 00:00:00 2001 From: amwx Date: Tue, 4 Aug 2020 23:15:12 -0500 Subject: [PATCH 169/344] Default theme support --- src/Avalonia.Themes.Default/Accents/BaseDark.xaml | 3 +++ src/Avalonia.Themes.Default/Accents/BaseLight.xaml | 3 +++ src/Avalonia.Themes.Default/DefaultTheme.xaml | 3 +++ 3 files changed, 9 insertions(+) diff --git a/src/Avalonia.Themes.Default/Accents/BaseDark.xaml b/src/Avalonia.Themes.Default/Accents/BaseDark.xaml index 4274f7ee4d..44dfb9ea48 100644 --- a/src/Avalonia.Themes.Default/Accents/BaseDark.xaml +++ b/src/Avalonia.Themes.Default/Accents/BaseDark.xaml @@ -58,6 +58,9 @@ + + + 1,1,1,1 diff --git a/src/Avalonia.Themes.Default/Accents/BaseLight.xaml b/src/Avalonia.Themes.Default/Accents/BaseLight.xaml index b1c0946d0f..9ed3207235 100644 --- a/src/Avalonia.Themes.Default/Accents/BaseLight.xaml +++ b/src/Avalonia.Themes.Default/Accents/BaseLight.xaml @@ -61,6 +61,9 @@ + + + 1 diff --git a/src/Avalonia.Themes.Default/DefaultTheme.xaml b/src/Avalonia.Themes.Default/DefaultTheme.xaml index 4e63d1d223..e5b654b490 100644 --- a/src/Avalonia.Themes.Default/DefaultTheme.xaml +++ b/src/Avalonia.Themes.Default/DefaultTheme.xaml @@ -55,4 +55,7 @@ + + + From 4f7a701ab79044ba29a23e65a48446271ff81dfc Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Wed, 5 Aug 2020 06:35:37 +0200 Subject: [PATCH 170/344] Reuse the shaped text runs as much as possible --- .../Media/TextFormatting/TextFormatterImpl.cs | 79 +++++++++++++------ .../Media/TextFormatting/TextLayout.cs | 5 +- .../Media/TextFormatting/TextLineImpl.cs | 4 +- src/Skia/Avalonia.Skia/TextShaperImpl.cs | 10 +-- 4 files changed, 62 insertions(+), 36 deletions(-) diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs index 9318fcc68e..b116249fd4 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs +++ b/src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs @@ -31,7 +31,8 @@ namespace Avalonia.Media.TextFormatting case TextWrapping.WrapWithOverflow: case TextWrapping.Wrap: { - textLine = PerformTextWrapping(textRuns, textRange, paragraphWidth, paragraphProperties); + textLine = PerformTextWrapping(textRuns, textRange, paragraphWidth, paragraphProperties, + nextLineBreak); break; } default: @@ -118,7 +119,7 @@ namespace Avalonia.Media.TextFormatting /// The text run's. /// The length to split at. /// The split text runs. - internal static SplitTextRunsResult SplitTextRuns(IReadOnlyList textRuns, int length) + internal static SplitTextRunsResult SplitTextRuns(List textRuns, int length) { var currentLength = 0; @@ -134,13 +135,13 @@ namespace Avalonia.Media.TextFormatting var firstCount = currentRun.GlyphRun.Characters.Length >= 1 ? i + 1 : i; - var first = new ShapedTextCharacters[firstCount]; + var first = new List(firstCount); if (firstCount > 1) { for (var j = 0; j < i; j++) { - first[j] = textRuns[j]; + first.Add(textRuns[j]); } } @@ -148,7 +149,7 @@ namespace Avalonia.Media.TextFormatting if (currentLength + currentRun.GlyphRun.Characters.Length == length) { - var second = new ShapedTextCharacters[secondCount]; + var second = new List(secondCount); var offset = currentRun.GlyphRun.Characters.Length > 1 ? 1 : 0; @@ -156,11 +157,11 @@ namespace Avalonia.Media.TextFormatting { for (var j = 0; j < secondCount; j++) { - second[j] = textRuns[i + j + offset]; + second.Add(textRuns[i + j + offset]); } } - first[i] = currentRun; + first.Add(currentRun); return new SplitTextRunsResult(first, second); } @@ -168,22 +169,22 @@ namespace Avalonia.Media.TextFormatting { secondCount++; - var second = new ShapedTextCharacters[secondCount]; + var second = new List(secondCount); + + var split = currentRun.Split(length - currentLength); + + first.Add(split.First); + + second.Add(split.Second); if (secondCount > 0) { for (var j = 1; j < secondCount; j++) { - second[j] = textRuns[i + j]; + second.Add(textRuns[i + j]); } } - var split = currentRun.Split(length - currentLength); - - first[i] = split.First; - - second[0] = split.Second; - return new SplitTextRunsResult(first, second); } } @@ -201,7 +202,7 @@ namespace Avalonia.Media.TextFormatting /// /// The formatted text runs. /// - private static IReadOnlyList FetchTextRuns(ITextSource textSource, + private static List FetchTextRuns(ITextSource textSource, int firstTextSourceIndex, TextLineBreak previousLineBreak, out TextLineBreak nextLineBreak) { nextLineBreak = default; @@ -212,8 +213,10 @@ namespace Avalonia.Media.TextFormatting if (previousLineBreak != null) { - foreach (var shapedCharacters in previousLineBreak.RemainingCharacters) + for (var index = 0; index < previousLineBreak.RemainingCharacters.Count; index++) { + var shapedCharacters = previousLineBreak.RemainingCharacters[index]; + if (shapedCharacters == null) { continue; @@ -225,6 +228,14 @@ namespace Avalonia.Media.TextFormatting { var splitResult = SplitTextRuns(textRuns, currentLength + runLineBreak.PositionWrap); + if (++index < previousLineBreak.RemainingCharacters.Count) + { + for (; index < previousLineBreak.RemainingCharacters.Count; index++) + { + splitResult.Second.Add(previousLineBreak.RemainingCharacters[index]); + } + } + nextLineBreak = new TextLineBreak(splitResult.Second); return splitResult.First; @@ -323,9 +334,10 @@ namespace Avalonia.Media.TextFormatting /// The text range that is covered by the text runs. /// The paragraph width. /// The text paragraph properties. + /// The current line break if the line was explicitly broken. /// The wrapped text line. - private static TextLine PerformTextWrapping(IReadOnlyList textRuns, TextRange textRange, - double paragraphWidth, TextParagraphProperties paragraphProperties) + private static TextLine PerformTextWrapping(List textRuns, TextRange textRange, + double paragraphWidth, TextParagraphProperties paragraphProperties, TextLineBreak currentLineBreak) { var availableWidth = paragraphWidth; var currentWidth = 0.0; @@ -388,8 +400,22 @@ namespace Avalonia.Media.TextFormatting var textLineMetrics = TextLineMetrics.Create(splitResult.First, new TextRange(textRange.Start, currentLength), paragraphWidth, paragraphProperties); - var lineBreak = splitResult.Second != null && splitResult.Second.Count > 0 ? - new TextLineBreak(splitResult.Second) : + var remainingCharacters = splitResult.Second; + + if (currentLineBreak?.RemainingCharacters != null) + { + if (remainingCharacters != null) + { + remainingCharacters.AddRange(currentLineBreak.RemainingCharacters); + } + else + { + remainingCharacters = new List(currentLineBreak.RemainingCharacters); + } + } + + var lineBreak = remainingCharacters != null && remainingCharacters.Count > 0 ? + new TextLineBreak(remainingCharacters) : null; return new TextLineImpl(splitResult.First, textLineMetrics, lineBreak); @@ -403,7 +429,10 @@ namespace Avalonia.Media.TextFormatting } return new TextLineImpl(textRuns, - TextLineMetrics.Create(textRuns, textRange, paragraphWidth, paragraphProperties)); + TextLineMetrics.Create(textRuns, textRange, paragraphWidth, paragraphProperties), + currentLineBreak?.RemainingCharacters != null ? + new TextLineBreak(currentLineBreak.RemainingCharacters) : + null); } /// @@ -434,7 +463,7 @@ namespace Avalonia.Media.TextFormatting internal readonly struct SplitTextRunsResult { - public SplitTextRunsResult(IReadOnlyList first, IReadOnlyList second) + public SplitTextRunsResult(List first, List second) { First = first; @@ -447,7 +476,7 @@ namespace Avalonia.Media.TextFormatting /// /// The first text runs. /// - public IReadOnlyList First { get; } + public List First { get; } /// /// Gets the second text runs. @@ -455,7 +484,7 @@ namespace Avalonia.Media.TextFormatting /// /// The second text runs. /// - public IReadOnlyList Second { get; } + public List Second { get; } } private struct TextRunEnumerator diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs index 14602a2560..fa7d6cb4bf 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs +++ b/src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs @@ -183,7 +183,10 @@ namespace Avalonia.Media.TextFormatting var glyphRun = TextShaper.Current.ShapeText(new ReadOnlySlice(s_empty, startingIndex, 1), properties.Typeface, properties.FontRenderingEmSize, properties.CultureInfo); - var textRuns = new[] { new ShapedTextCharacters(glyphRun, _paragraphProperties.DefaultTextRunProperties) }; + var textRuns = new List + { + new ShapedTextCharacters(glyphRun, _paragraphProperties.DefaultTextRunProperties) + }; return new TextLineImpl(textRuns, TextLineMetrics.Create(textRuns, new TextRange(startingIndex, 1), MaxWidth, _paragraphProperties)); diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs index 435752160e..8b44e32c48 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs +++ b/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs @@ -6,9 +6,9 @@ namespace Avalonia.Media.TextFormatting { internal class TextLineImpl : TextLine { - private readonly IReadOnlyList _textRuns; + private readonly List _textRuns; - public TextLineImpl(IReadOnlyList textRuns, TextLineMetrics lineMetrics, + public TextLineImpl(List textRuns, TextLineMetrics lineMetrics, TextLineBreak lineBreak = null, bool hasCollapsed = false) { _textRuns = textRuns; diff --git a/src/Skia/Avalonia.Skia/TextShaperImpl.cs b/src/Skia/Avalonia.Skia/TextShaperImpl.cs index b0384a1fdf..61075171fe 100644 --- a/src/Skia/Avalonia.Skia/TextShaperImpl.cs +++ b/src/Skia/Avalonia.Skia/TextShaperImpl.cs @@ -123,10 +123,7 @@ namespace Avalonia.Skia return; } - if (offsetBuffer == null) - { - offsetBuffer = new Vector[glyphPositions.Length]; - } + offsetBuffer ??= new Vector[glyphPositions.Length]; var offsetX = position.XOffset * textScale; @@ -138,10 +135,7 @@ namespace Avalonia.Skia private static void SetAdvance(ReadOnlySpan glyphPositions, int index, double textScale, ref double[] advanceBuffer) { - if (advanceBuffer == null) - { - advanceBuffer = new double[glyphPositions.Length]; - } + advanceBuffer ??= new double[glyphPositions.Length]; // Depends on direction of layout // advanceBuffer[index] = buffer.GlyphPositions[index].YAdvance * textScale; From 922c46bbc4d125a005164c942cc1af70729afd6a Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 5 Aug 2020 14:38:30 +0200 Subject: [PATCH 171/344] Dispose the grid hack in the correct place. The grid hack was initiated when attached to the visual tree but the dispose had been placed in `OnDetachedFromLogicalTree` by mistake. Place it in `OnDetachedFromVisualTree`. --- src/Avalonia.Controls/MenuItem.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Avalonia.Controls/MenuItem.cs b/src/Avalonia.Controls/MenuItem.cs index 912abc6de3..2a22896de1 100644 --- a/src/Avalonia.Controls/MenuItem.cs +++ b/src/Avalonia.Controls/MenuItem.cs @@ -323,9 +323,6 @@ namespace Avalonia.Controls { Command.CanExecuteChanged -= CanExecuteChanged; } - - _gridHack?.Dispose(); - _gridHack = null; } protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) @@ -351,6 +348,14 @@ namespace Avalonia.Controls } } + protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) + { + base.OnDetachedFromVisualTree(e); + + _gridHack?.Dispose(); + _gridHack = null; + } + /// /// Called when the is clicked. /// From a91d6322112c679e96dc8968280bf62832139b9e Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 5 Aug 2020 16:33:09 +0200 Subject: [PATCH 172/344] Move ListBox page view model to its own file. Also remove `SelectedItem` and `SelectedItems` in favor of `SelectionModel`. --- samples/ControlCatalog/Pages/ListBoxPage.xaml | 3 +- .../ControlCatalog/Pages/ListBoxPage.xaml.cs | 68 +------------------ .../ViewModels/ListBoxPageViewModel.cs | 65 ++++++++++++++++++ 3 files changed, 68 insertions(+), 68 deletions(-) create mode 100644 samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs diff --git a/samples/ControlCatalog/Pages/ListBoxPage.xaml b/samples/ControlCatalog/Pages/ListBoxPage.xaml index f4d81418ac..edf3d41bf5 100644 --- a/samples/ControlCatalog/Pages/ListBoxPage.xaml +++ b/samples/ControlCatalog/Pages/ListBoxPage.xaml @@ -11,8 +11,7 @@ Spacing="16"> (Enumerable.Range(1, 10000).Select(i => GenerateItem())); - SelectedItems = new ObservableCollection(); - - AddItemCommand = ReactiveCommand.Create(() => Items.Add(GenerateItem())); - - RemoveItemCommand = ReactiveCommand.Create(() => - { - while (SelectedItems.Count > 0) - { - Items.Remove(SelectedItems[0]); - } - }); - - SelectRandomItemCommand = ReactiveCommand.Create(() => - { - var random = new Random(); - - SelectedItem = Items[random.Next(Items.Count - 1)]; - }); - } - - public ObservableCollection Items { get; } - - private string _selectedItem; - - public string SelectedItem - { - get { return _selectedItem; } - set { this.RaiseAndSetIfChanged(ref _selectedItem, value); } - } - - - public ObservableCollection SelectedItems { get; } - - public ReactiveCommand AddItemCommand { get; } - - public ReactiveCommand RemoveItemCommand { get; } - - public ReactiveCommand SelectRandomItemCommand { get; } - - public SelectionMode SelectionMode - { - get => _selectionMode; - set - { - SelectedItems.Clear(); - this.RaiseAndSetIfChanged(ref _selectionMode, value); - } - } - - private string GenerateItem() => $"Item {_counter++.ToString()}"; - } } } diff --git a/samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs b/samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs new file mode 100644 index 0000000000..6bdb5c0103 --- /dev/null +++ b/samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.ObjectModel; +using System.Linq; +using System.Reactive; +using Avalonia.Controls; +using ReactiveUI; + +namespace ControlCatalog.ViewModels +{ + public class ListBoxPageViewModel : ReactiveObject + { + private int _counter; + private SelectionMode _selectionMode; + + public ListBoxPageViewModel() + { + Items = new ObservableCollection(Enumerable.Range(1, 10000).Select(i => GenerateItem())); + Selection = new SelectionModel(); + Selection.Select(1); + + AddItemCommand = ReactiveCommand.Create(() => Items.Add(GenerateItem())); + + RemoveItemCommand = ReactiveCommand.Create(() => + { + while (Selection.SelectedItems.Count > 0) + { + Items.Remove((string)Selection.SelectedItems.First()); + } + }); + + SelectRandomItemCommand = ReactiveCommand.Create(() => + { + var random = new Random(); + + using (Selection.Update()) + { + Selection.ClearSelection(); + Selection.Select(random.Next(Items.Count - 1)); + } + }); + } + + public ObservableCollection Items { get; } + + public SelectionModel Selection { get; } + + public ReactiveCommand AddItemCommand { get; } + + public ReactiveCommand RemoveItemCommand { get; } + + public ReactiveCommand SelectRandomItemCommand { get; } + + public SelectionMode SelectionMode + { + get => _selectionMode; + set + { + Selection.ClearSelection(); + this.RaiseAndSetIfChanged(ref _selectionMode, value); + } + } + + private string GenerateItem() => $"Item {_counter++.ToString()}"; + } +} From d2af884aedf68f4534e2afa20e4c282cc4e7eba2 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 5 Aug 2020 17:13:02 +0200 Subject: [PATCH 173/344] Added a failing test for #4272. --- .../Utils/SelectedItemsSyncTests.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/Avalonia.Controls.UnitTests/Utils/SelectedItemsSyncTests.cs b/tests/Avalonia.Controls.UnitTests/Utils/SelectedItemsSyncTests.cs index 3ab5950974..4aa7e24aa7 100644 --- a/tests/Avalonia.Controls.UnitTests/Utils/SelectedItemsSyncTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Utils/SelectedItemsSyncTests.cs @@ -208,6 +208,20 @@ namespace Avalonia.Controls.UnitTests.Utils target.SetItems(new[] { "foo", "bar", "baz" })); } + [Fact] + public void Selected_Items_Can_Be_Set_Before_SelectionModel_Source() + { + var model = new SelectionModel(); + var target = new SelectedItemsSync(model); + var items = new AvaloniaList { "foo", "bar", "baz" }; + var selectedItems = new AvaloniaList { "bar" }; + + target.SetItems(selectedItems); + model.Source = items; + + Assert.Equal(new IndexPath(1), model.SelectedIndex); + } + private static SelectedItemsSync CreateTarget( IEnumerable items = null) { From 0f9ac73b4fc43dde5384e7eb4825a87e0266446f Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 5 Aug 2020 17:13:18 +0200 Subject: [PATCH 174/344] Handle uninitialized Source in SelectedItemsSync. If the `SelectionModel` passed to `SelectedItemsSync` has not yet had a `Source` assigned, set a flag to write the selected items to the `SelectionModel` when `Source` is set. Fixes #4272 --- .../Utils/SelectedItemsSync.cs | 37 +++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/src/Avalonia.Controls/Utils/SelectedItemsSync.cs b/src/Avalonia.Controls/Utils/SelectedItemsSync.cs index c127771990..91cef9fe64 100644 --- a/src/Avalonia.Controls/Utils/SelectedItemsSync.cs +++ b/src/Avalonia.Controls/Utils/SelectedItemsSync.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Specialized; +using System.ComponentModel; using System.Linq; using Avalonia.Collections; @@ -16,6 +17,7 @@ namespace Avalonia.Controls.Utils private IList? _items; private bool _updatingItems; private bool _updatingModel; + private bool _initializeOnSourceAssignment; public SelectedItemsSync(ISelectionModel model) { @@ -63,10 +65,18 @@ namespace Avalonia.Controls.Utils _updatingModel = true; _items = items; - using (Model.Update()) + if (Model.Source is object) { - Model.ClearSelection(); - Add(items); + using (Model.Update()) + { + Model.ClearSelection(); + Add(items); + } + } + else if (!_initializeOnSourceAssignment) + { + Model.PropertyChanged += SelectionModelPropertyChanged; + _initializeOnSourceAssignment = true; } if (_items is INotifyCollectionChanged incc2) @@ -86,9 +96,11 @@ namespace Avalonia.Controls.Utils if (_items != null) { + Model.PropertyChanged -= SelectionModelPropertyChanged; Model.SelectionChanged -= SelectionModelSelectionChanged; Model = model; Model.SelectionChanged += SelectionModelSelectionChanged; + _initializeOnSourceAssignment = false; try { @@ -175,6 +187,25 @@ namespace Avalonia.Controls.Utils } } + private void SelectionModelPropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (_initializeOnSourceAssignment && + _items != null && + e.PropertyName == nameof(SelectionModel.Source)) + { + try + { + _updatingModel = true; + Add(_items); + _initializeOnSourceAssignment = false; + } + finally + { + _updatingModel = false; + } + } + } + private void SelectionModelSelectionChanged(object sender, SelectionModelSelectionChangedEventArgs e) { if (_updatingModel) From db67fa2cf6c4918a99006528567e2db1c2e0ea26 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 5 Aug 2020 23:57:45 +0200 Subject: [PATCH 175/344] Tweak the MenuItem Grid hack. To try and fix menu layout in the fluent theme. --- src/Avalonia.Controls/MenuItem.cs | 59 ++++++++++++++----------------- 1 file changed, 27 insertions(+), 32 deletions(-) diff --git a/src/Avalonia.Controls/MenuItem.cs b/src/Avalonia.Controls/MenuItem.cs index 2a22896de1..bfa2e81745 100644 --- a/src/Avalonia.Controls/MenuItem.cs +++ b/src/Avalonia.Controls/MenuItem.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reactive.Linq; using System.Windows.Input; using Avalonia.Controls.Generators; using Avalonia.Controls.Mixins; @@ -97,7 +98,6 @@ namespace Avalonia.Controls private ICommand _command; private bool _commandCanExecute = true; private Popup _popup; - private IDisposable _gridHack; /// /// Initializes static members of the class. @@ -119,6 +119,32 @@ namespace Avalonia.Controls public MenuItem() { + // HACK: This nasty but it's all WPF's fault. Grid uses an inherited attached + // property to store SharedSizeGroup state, except property inheritance is done + // down the logical tree. In this case, the control which is setting + // Grid.IsSharedSizeScope="True" is not in the logical tree. Instead of fixing + // the way Grid stores shared size state, the developers of WPF just created a + // binding of the internal state of the visual parent to the menu item. We don't + // have much choice but to do the same for now unless we want to refactor Grid, + // which I honestly am not brave enough to do right now. Here's the same hack in + // the WPF codebase: + // + // https://github.com/dotnet/wpf/blob/89537909bdf36bc918e88b37751add46a8980bb0/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/MenuItem.cs#L2126-L2141 + // + // In addition to the hack from WPF, we also make sure to return null when we have + // no parent. If we don't do this, inheritance falls back to the logical tree, + // causing the shared size scope in the parent MenuItem to be used, breaking + // menu layout. + + var parentSharedSizeScope = this.GetObservable(VisualParentProperty) + .SelectMany(x => + { + var parent = x as Control; + return parent?.GetObservable(DefinitionBase.PrivateSharedSizeScopeProperty) ?? + Observable.Return(null); + }); + + this.Bind(DefinitionBase.PrivateSharedSizeScopeProperty, parentSharedSizeScope); } /// @@ -325,37 +351,6 @@ namespace Avalonia.Controls } } - protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) - { - base.OnAttachedToVisualTree(e); - - if (this.GetVisualParent() is IControl parent) - { - // HACK: This nasty but it's all WPF's fault. Grid uses an inherited attached - // property to store SharedSizeGroup state, except property inheritance is done - // down the logical tree. In this case, the control which is setting - // Grid.IsSharedSizeScope="True" is not in the logical tree. Instead of fixing - // the way Grid stores shared size state, the developers of WPF just created a - // binding of the internal state of the visual parent to the menu item. We don't - // have much choice but to do the same for now unless we want to refactor Grid, - // which I honestly am not brave enough to do right now. Here's the same hack in - // the WPF codebase: - // - // https://github.com/dotnet/wpf/blob/89537909bdf36bc918e88b37751add46a8980bb0/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/MenuItem.cs#L2126-L2141 - _gridHack = Bind( - DefinitionBase.PrivateSharedSizeScopeProperty, - parent.GetBindingObservable(DefinitionBase.PrivateSharedSizeScopeProperty)); - } - } - - protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) - { - base.OnDetachedFromVisualTree(e); - - _gridHack?.Dispose(); - _gridHack = null; - } - /// /// Called when the is clicked. /// From 15e78765308e42716332c4c737272e775509ebec Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 6 Aug 2020 16:42:51 +0200 Subject: [PATCH 176/344] Fix incorrect argument ordering. --- .../Repeater/ItemsRepeaterElementIndexChangedEventArgs.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/Repeater/ItemsRepeaterElementIndexChangedEventArgs.cs b/src/Avalonia.Controls/Repeater/ItemsRepeaterElementIndexChangedEventArgs.cs index bf1b80f947..9f1c32bf64 100644 --- a/src/Avalonia.Controls/Repeater/ItemsRepeaterElementIndexChangedEventArgs.cs +++ b/src/Avalonia.Controls/Repeater/ItemsRepeaterElementIndexChangedEventArgs.cs @@ -34,7 +34,7 @@ namespace Avalonia.Controls /// public int OldIndex { get; private set; } - internal void Update(IControl element, int newIndex, int oldIndex) + internal void Update(IControl element, int oldIndex, int newIndex) { Element = element; NewIndex = newIndex; From 472352558f24c7be59c9bfd86a6129d600ae6e82 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 6 Aug 2020 17:13:34 +0200 Subject: [PATCH 177/344] Added failing test for #4403. --- tests/Avalonia.Styling.UnitTests/SetterTests.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/Avalonia.Styling.UnitTests/SetterTests.cs b/tests/Avalonia.Styling.UnitTests/SetterTests.cs index 46cde30b8a..901233801e 100644 --- a/tests/Avalonia.Styling.UnitTests/SetterTests.cs +++ b/tests/Avalonia.Styling.UnitTests/SetterTests.cs @@ -35,6 +35,21 @@ namespace Avalonia.Styling.UnitTests Assert.Equal("foo", control.Text); } + [Fact] + public void Setter_Should_Handle_Binding_Producing_UnsetValue() + { + var control = new TextBlock(); + var subject = new BehaviorSubject(AvaloniaProperty.UnsetValue); + var descriptor = InstancedBinding.OneWay(subject); + var binding = Mock.Of(x => x.Initiate(control, TextBlock.TagProperty, null, false) == descriptor); + var style = Mock.Of(); + var setter = new Setter(TextBlock.TagProperty, binding); + + setter.Instance(control).Start(false); + + Assert.Equal("", control.Text); + } + [Fact] public void Setter_Should_Materialize_Template_To_Property() { From de8171f8ac2221095bd9129636d754194992884b Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 6 Aug 2020 17:13:49 +0200 Subject: [PATCH 178/344] Correctly handle UnsetValue/DoNothing in setters. Just need to call `BindingValue.FromUntyped` instead of doing a conditional, because otherwise we run the risk of passing `UnsetValue` to the `BindingValue` ctor which will throw in that case. --- src/Avalonia.Styling/Styling/PropertySetterBindingInstance.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Styling/Styling/PropertySetterBindingInstance.cs b/src/Avalonia.Styling/Styling/PropertySetterBindingInstance.cs index e177993d13..929f7142bb 100644 --- a/src/Avalonia.Styling/Styling/PropertySetterBindingInstance.cs +++ b/src/Avalonia.Styling/Styling/PropertySetterBindingInstance.cs @@ -164,7 +164,7 @@ namespace Avalonia.Styling private void ConvertAndPublishNext(object? value) { - _value = value is T v ? v : BindingValue.FromUntyped(value); + _value = BindingValue.FromUntyped(value); if (_isActive) { From e74a0d9698e1937ca46b17a330e7669ca041c3f8 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 7 Aug 2020 14:25:31 +0200 Subject: [PATCH 179/344] Make ItemsRepeater work with no ScrollViewer. There doesn't seem to be any reason to make `ItemsRepeater` not work properly when there's no `ScrollViewer`. Fixes #4330 --- src/Avalonia.Controls/Repeater/ViewportManager.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/Avalonia.Controls/Repeater/ViewportManager.cs b/src/Avalonia.Controls/Repeater/ViewportManager.cs index 0d22187b34..796ae8616d 100644 --- a/src/Avalonia.Controls/Repeater/ViewportManager.cs +++ b/src/Avalonia.Controls/Repeater/ViewportManager.cs @@ -469,13 +469,7 @@ namespace Avalonia.Controls parent = parent.VisualParent; } - if (_scroller == null) - { - // We usually update the viewport in the post arrange handler. But, since we don't have - // a scroller, let's do it now. - UpdateViewport(Rect.Empty); - } - else if (!_managingViewportDisabled) + if (!_managingViewportDisabled) { _owner.EffectiveViewportChanged += OnEffectiveViewportChanged; _effectiveViewportChangedSubscribed = true; From 2337da31b1367b57c61ff70b1489f7817d31be6b Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 7 Aug 2020 15:17:18 +0200 Subject: [PATCH 180/344] Add null check for scroller. --- src/Avalonia.Controls/Repeater/ViewportManager.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Avalonia.Controls/Repeater/ViewportManager.cs b/src/Avalonia.Controls/Repeater/ViewportManager.cs index 796ae8616d..bdb0fa3270 100644 --- a/src/Avalonia.Controls/Repeater/ViewportManager.cs +++ b/src/Avalonia.Controls/Repeater/ViewportManager.cs @@ -350,11 +350,14 @@ namespace Avalonia.Controls } // Make sure that only the target child can be the anchor during the bring into view operation. - foreach (var child in _owner.Children) + if (_scroller is object) { - if (child != targetChild) + foreach (var child in _owner.Children) { - _scroller.UnregisterAnchorCandidate(child); + if (child != targetChild) + { + _scroller.UnregisterAnchorCandidate(child); + } } } From c5c12393f6c9c495fea9215aac4a635475bce7fa Mon Sep 17 00:00:00 2001 From: Rustam Sayfutdinov Date: Fri, 7 Aug 2020 20:07:46 +0300 Subject: [PATCH 181/344] Fix typo in FontSizeNormal --- src/Avalonia.Themes.Default/Window.xaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Themes.Default/Window.xaml b/src/Avalonia.Themes.Default/Window.xaml index 7d74a7e6a0..3b378dbcbe 100644 --- a/src/Avalonia.Themes.Default/Window.xaml +++ b/src/Avalonia.Themes.Default/Window.xaml @@ -2,7 +2,7 @@ - + From 22866e869496314551520fa1e5e2c85d721cf592 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Pedro?= Date: Fri, 7 Aug 2020 17:35:05 +0100 Subject: [PATCH 182/344] Fixed item type inference for ItemsRepeater in compiled bindings. --- .../AvaloniaXamlIlDataContextTypeTransformer.cs | 13 ++++++++++--- .../Transformers/AvaloniaXamlIlWellKnownTypes.cs | 2 ++ 2 files changed, 12 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 241976241f..c4d67deb4c 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs @@ -74,11 +74,18 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers { // Infer data type from collection binding on a control that displays items. var parentObject = context.ParentNodes().OfType().FirstOrDefault(); - if (parentObject != null && context.GetAvaloniaTypes().IItemsPresenterHost.IsDirectlyAssignableFrom(parentObject.Type.GetClrType())) + if (parentObject != null) { - inferredDataContextTypeNode = InferDataContextOfPresentedItem(context, on, parentObject); + var parentType = parentObject.Type.GetClrType(); + + if (context.GetAvaloniaTypes().IItemsPresenterHost.IsDirectlyAssignableFrom(parentType) + || context.GetAvaloniaTypes().ItemsRepeater.IsDirectlyAssignableFrom(parentType)) + { + inferredDataContextTypeNode = InferDataContextOfPresentedItem(context, on, parentObject); + } } - else + + if (inferredDataContextTypeNode is null) { inferredDataContextTypeNode = new AvaloniaXamlIlUninferrableDataContextMetadataNode(on); } 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 58ea11aa8f..f4ca76c21c 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs @@ -42,6 +42,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers public IXamlType DataTemplate { get; } public IXamlType IItemsPresenterHost { get; } + public IXamlType ItemsRepeater { get; } public IXamlType ReflectionBindingExtension { get; } public IXamlType RelativeSource { get; } @@ -98,6 +99,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers ResolveByNameExtension = cfg.TypeSystem.GetType("Avalonia.Markup.Xaml.MarkupExtensions.ResolveByNameExtension"); DataTemplate = cfg.TypeSystem.GetType("Avalonia.Markup.Xaml.Templates.DataTemplate"); IItemsPresenterHost = cfg.TypeSystem.GetType("Avalonia.Controls.Presenters.IItemsPresenterHost"); + ItemsRepeater = cfg.TypeSystem.GetType("Avalonia.Controls.ItemsRepeater"); ReflectionBindingExtension = cfg.TypeSystem.GetType("Avalonia.Markup.Xaml.MarkupExtensions.ReflectionBindingExtension"); RelativeSource = cfg.TypeSystem.GetType("Avalonia.Data.RelativeSource"); } From aed62ca4a71bb6e77d37035b97b4c9aacde63b3a Mon Sep 17 00:00:00 2001 From: Maksym Katsydan Date: Fri, 7 Aug 2020 16:02:37 -0400 Subject: [PATCH 183/344] Fluent: Add missing MenuItem Header styles --- samples/ControlCatalog/Pages/MenuPage.xaml | 4 ++++ src/Avalonia.Themes.Fluent/MenuItem.xaml | 14 ++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/samples/ControlCatalog/Pages/MenuPage.xaml b/samples/ControlCatalog/Pages/MenuPage.xaml index e9d2301e89..45564f3e41 100644 --- a/samples/ControlCatalog/Pages/MenuPage.xaml +++ b/samples/ControlCatalog/Pages/MenuPage.xaml @@ -17,12 +17,16 @@ + + + + diff --git a/src/Avalonia.Themes.Fluent/MenuItem.xaml b/src/Avalonia.Themes.Fluent/MenuItem.xaml index 2115319c3c..3a03ec1acf 100644 --- a/src/Avalonia.Themes.Fluent/MenuItem.xaml +++ b/src/Avalonia.Themes.Fluent/MenuItem.xaml @@ -8,6 +8,8 @@ Height="200"> + @@ -83,7 +85,6 @@ Content="{TemplateBinding Header}" VerticalAlignment="Center" HorizontalAlignment="Stretch" - TextBlock.Foreground="{TemplateBinding Foreground}" Grid.Column="1"> @@ -213,6 +214,9 @@ + @@ -224,6 +228,9 @@ + @@ -231,9 +238,12 @@ - + From 63a4333832300f4d823f1bb6da755d1f017ffeda Mon Sep 17 00:00:00 2001 From: Maksym Katsydan Date: Fri, 7 Aug 2020 16:53:29 -0400 Subject: [PATCH 184/344] ControlCatalog: Update ContextMenuPage and MenuPage samples --- samples/ControlCatalog/App.xaml | 2 +- samples/ControlCatalog/Pages/ContextMenuPage.xaml | 5 +++-- samples/ControlCatalog/Pages/MenuPage.xaml | 4 ++-- src/Avalonia.Themes.Fluent/ContextMenu.xaml | 2 ++ 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/samples/ControlCatalog/App.xaml b/samples/ControlCatalog/App.xaml index 1c8c38d3e5..bab57f3544 100644 --- a/samples/ControlCatalog/App.xaml +++ b/samples/ControlCatalog/App.xaml @@ -11,7 +11,7 @@ diff --git a/samples/ControlCatalog/Pages/ContextMenuPage.xaml b/samples/ControlCatalog/Pages/ContextMenuPage.xaml index 8ccd8e97f7..260162ddb9 100644 --- a/samples/ControlCatalog/Pages/ContextMenuPage.xaml +++ b/samples/ControlCatalog/Pages/ContextMenuPage.xaml @@ -14,13 +14,14 @@ Padding="48,48,48,48"> - + + - + diff --git a/samples/ControlCatalog/Pages/MenuPage.xaml b/samples/ControlCatalog/Pages/MenuPage.xaml index 45564f3e41..2c09cb9b4d 100644 --- a/samples/ControlCatalog/Pages/MenuPage.xaml +++ b/samples/ControlCatalog/Pages/MenuPage.xaml @@ -16,8 +16,8 @@ Defined in XAML - - + + diff --git a/src/Avalonia.Themes.Fluent/ContextMenu.xaml b/src/Avalonia.Themes.Fluent/ContextMenu.xaml index a6b6156944..6ad038676b 100644 --- a/src/Avalonia.Themes.Fluent/ContextMenu.xaml +++ b/src/Avalonia.Themes.Fluent/ContextMenu.xaml @@ -9,6 +9,8 @@ + From 09b042683a51adbb7db402fefa3d8f86ac77edc9 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 10 Aug 2020 15:17:54 +0200 Subject: [PATCH 185/344] Move some tests. Tests for `AvaloniaObject.IsSet` were in the `Metadata` test class, though `IsSet` has nothing to do with metadata. Moved them into `SetValue` which is more relevant. --- .../AvaloniaObjectTests_Metadata.cs | 29 ------------------- .../AvaloniaObjectTests_SetValue.cs | 29 +++++++++++++++++++ 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Metadata.cs b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Metadata.cs index 8d04f817f1..c3f7b816f2 100644 --- a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Metadata.cs +++ b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Metadata.cs @@ -15,35 +15,6 @@ namespace Avalonia.Base.UnitTests p = AttachedOwner.AttachedProperty; } - [Fact] - public void IsSet_Returns_False_For_Unset_Property() - { - var target = new Class1(); - - Assert.False(target.IsSet(Class1.FooProperty)); - } - - [Fact] - public void IsSet_Returns_False_For_Set_Property() - { - var target = new Class1(); - - target.SetValue(Class1.FooProperty, "foo"); - - Assert.True(target.IsSet(Class1.FooProperty)); - } - - [Fact] - public void IsSet_Returns_False_For_Cleared_Property() - { - var target = new Class1(); - - target.SetValue(Class1.FooProperty, "foo"); - target.SetValue(Class1.FooProperty, AvaloniaProperty.UnsetValue); - - Assert.False(target.IsSet(Class1.FooProperty)); - } - private class Class1 : AvaloniaObject { public static readonly StyledProperty FooProperty = diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_SetValue.cs b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_SetValue.cs index 66a741e122..954a609315 100644 --- a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_SetValue.cs +++ b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_SetValue.cs @@ -39,6 +39,35 @@ namespace Avalonia.Base.UnitTests Assert.Equal(1, raised); } + [Fact] + public void IsSet_Returns_False_For_Unset_Property() + { + var target = new Class1(); + + Assert.False(target.IsSet(Class1.FooProperty)); + } + + [Fact] + public void IsSet_Returns_False_For_Set_Property() + { + var target = new Class1(); + + target.SetValue(Class1.FooProperty, "foo"); + + Assert.True(target.IsSet(Class1.FooProperty)); + } + + [Fact] + public void IsSet_Returns_False_For_Cleared_Property() + { + var target = new Class1(); + + target.SetValue(Class1.FooProperty, "foo"); + target.SetValue(Class1.FooProperty, AvaloniaProperty.UnsetValue); + + Assert.False(target.IsSet(Class1.FooProperty)); + } + [Fact] public void SetValue_Sets_Value() { From 7d2563de3a882543d8f2a497fa5b9bee7afec56e Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 10 Aug 2020 15:46:04 +0200 Subject: [PATCH 186/344] Expose OverrideMetadata for direct properties. --- src/Avalonia.Base/DirectPropertyBase.cs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/Avalonia.Base/DirectPropertyBase.cs b/src/Avalonia.Base/DirectPropertyBase.cs index d42c030245..334b90177b 100644 --- a/src/Avalonia.Base/DirectPropertyBase.cs +++ b/src/Avalonia.Base/DirectPropertyBase.cs @@ -102,6 +102,26 @@ namespace Avalonia return (DirectPropertyMetadata)base.GetMetadata(type); } + /// + /// Overrides the metadata for the property on the specified type. + /// + /// The type. + /// The metadata. + public void OverrideMetadata(DirectPropertyMetadata metadata) where T : IAvaloniaObject + { + base.OverrideMetadata(typeof(T), metadata); + } + + /// + /// Overrides the metadata for the property on the specified type. + /// + /// The type. + /// The metadata. + public void OverrideMetadata(Type type, DirectPropertyMetadata metadata) + { + base.OverrideMetadata(type, metadata); + } + /// public override void Accept(IAvaloniaPropertyVisitor vistor, ref TData data) { From 7519f857062672281341d3e733e08ca0213e6ef0 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 10 Aug 2020 16:23:04 +0200 Subject: [PATCH 187/344] Added property metadata tests. --- .../AvaloniaObjectTests_Metadata.cs | 98 ++++++++++++++++--- 1 file changed, 85 insertions(+), 13 deletions(-) diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Metadata.cs b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Metadata.cs index c3f7b816f2..161911dfd5 100644 --- a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Metadata.cs +++ b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Metadata.cs @@ -1,5 +1,4 @@ -using System.Linq; -using System.Reactive.Linq; +using System.Runtime.CompilerServices; using Xunit; namespace Avalonia.Base.UnitTests @@ -9,28 +8,101 @@ namespace Avalonia.Base.UnitTests public AvaloniaObjectTests_Metadata() { // Ensure properties are registered. - AvaloniaProperty p; - p = Class1.FooProperty; - p = Class2.BarProperty; - p = AttachedOwner.AttachedProperty; + RuntimeHelpers.RunClassConstructor(typeof(Class1).TypeHandle); + RuntimeHelpers.RunClassConstructor(typeof(Class2).TypeHandle); + RuntimeHelpers.RunClassConstructor(typeof(Class3).TypeHandle); + } + + public class StyledProperty : AvaloniaObjectTests_Metadata + { + [Fact] + public void Default_Value_Can_Be_Overridden_In_Derived_Class() + { + var baseValue = Class1.StyledProperty.GetDefaultValue(typeof(Class1)); + var derivedValue = Class1.StyledProperty.GetDefaultValue(typeof(Class2)); + + Assert.Equal("foo", baseValue); + Assert.Equal("bar", derivedValue); + } + + [Fact] + public void Default_Value_Can_Be_Overridden_In_AddOwnered_Property() + { + var baseValue = Class1.StyledProperty.GetDefaultValue(typeof(Class1)); + var addOwneredValue = Class1.StyledProperty.GetDefaultValue(typeof(Class3)); + + Assert.Equal("foo", baseValue); + Assert.Equal("baz", addOwneredValue); + } + } + + public class DirectProperty : AvaloniaObjectTests_Metadata + { + [Fact] + public void Unset_Value_Can_Be_Overridden_In_Derived_Class() + { + var baseValue = Class1.DirectProperty.GetUnsetValue(typeof(Class1)); + var derivedValue = Class1.DirectProperty.GetUnsetValue(typeof(Class2)); + + Assert.Equal("foo", baseValue); + Assert.Equal("bar", derivedValue); + } + + [Fact] + public void Unset_Value_Can_Be_Overridden_In_AddOwnered_Property() + { + var baseValue = Class1.DirectProperty.GetUnsetValue(typeof(Class1)); + var addOwneredValue = Class3.DirectProperty.GetUnsetValue(typeof(Class3)); + + Assert.Equal("foo", baseValue); + Assert.Equal("baz", addOwneredValue); + } } private class Class1 : AvaloniaObject { - public static readonly StyledProperty FooProperty = - AvaloniaProperty.Register("Foo"); + public static readonly StyledProperty StyledProperty = + AvaloniaProperty.Register("Styled", "foo"); + + public static readonly DirectProperty DirectProperty = + AvaloniaProperty.RegisterDirect("Styled", o => o.Direct, unsetValue: "foo"); + + private string _direct; + + public string Direct + { + get => _direct; + } } private class Class2 : Class1 { - public static readonly StyledProperty BarProperty = - AvaloniaProperty.Register("Bar"); + static Class2() + { + StyledProperty.OverrideDefaultValue("bar"); + DirectProperty.OverrideMetadata(new DirectPropertyMetadata("bar")); + } } - private class AttachedOwner + private class Class3 : AvaloniaObject { - public static readonly AttachedProperty AttachedProperty = - AvaloniaProperty.RegisterAttached("Attached"); + public static readonly StyledProperty StyledProperty = + Class1.StyledProperty.AddOwner(); + + public static readonly DirectProperty DirectProperty = + Class1.DirectProperty.AddOwner(o => o.Direct, unsetValue: "baz"); + + private string _direct; + + static Class3() + { + StyledProperty.OverrideDefaultValue("baz"); + } + + public string Direct + { + get => _direct; + } } } } From 3e2e49bda45d49f2feb684f52609b9455f43aaad Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 10 Aug 2020 18:22:12 +0200 Subject: [PATCH 188/344] Bump version to 0.10.999 for CI builds. Now that 0.10 is (nearly) out, bump version on master. --- build/SharedVersion.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/SharedVersion.props b/build/SharedVersion.props index bd183faab3..d3cebef418 100644 --- a/build/SharedVersion.props +++ b/build/SharedVersion.props @@ -2,7 +2,7 @@ xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> Avalonia - 0.9.999 + 0.10.999 Copyright 2020 © The AvaloniaUI Project https://avaloniaui.net https://github.com/AvaloniaUI/Avalonia/ From f23bfafbaef806b380013ddd7a22a2da190bbf06 Mon Sep 17 00:00:00 2001 From: artyom Date: Mon, 10 Aug 2020 22:40:59 +0300 Subject: [PATCH 189/344] Show default content when Router is null --- src/Avalonia.ReactiveUI/RoutedViewHost.cs | 8 +++++ .../RoutedViewHostTest.cs | 34 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/src/Avalonia.ReactiveUI/RoutedViewHost.cs b/src/Avalonia.ReactiveUI/RoutedViewHost.cs index 1af8012a20..5520121033 100644 --- a/src/Avalonia.ReactiveUI/RoutedViewHost.cs +++ b/src/Avalonia.ReactiveUI/RoutedViewHost.cs @@ -66,6 +66,7 @@ namespace Avalonia.ReactiveUI this.WhenActivated(disposables => { this.WhenAnyObservable(x => x.Router.CurrentViewModel) + .StartWith(default(object)) .DistinctUntilChanged() .Subscribe(NavigateToViewModel) .DisposeWith(disposables); @@ -92,6 +93,13 @@ namespace Avalonia.ReactiveUI /// ViewModel to which the user navigates. private void NavigateToViewModel(object viewModel) { + if (Router == null) + { + this.Log().Warn("Router property is null. Falling back to default content."); + Content = DefaultContent; + return; + } + if (viewModel == null) { this.Log().Info("ViewModel is null. Falling back to default content."); diff --git a/tests/Avalonia.ReactiveUI.UnitTests/RoutedViewHostTest.cs b/tests/Avalonia.ReactiveUI.UnitTests/RoutedViewHostTest.cs index f4d9222085..5b7f7fe336 100644 --- a/tests/Avalonia.ReactiveUI.UnitTests/RoutedViewHostTest.cs +++ b/tests/Avalonia.ReactiveUI.UnitTests/RoutedViewHostTest.cs @@ -108,5 +108,39 @@ namespace Avalonia.ReactiveUI.UnitTests Assert.Equal(typeof(TextBlock), host.Content.GetType()); Assert.Equal(defaultContent, host.Content); } + + [Fact] + public void RoutedViewHost_Should_Show_Default_Content_When_Router_Is_Null() + { + var screen = new ScreenViewModel(); + var defaultContent = new TextBlock(); + var host = new RoutedViewHost + { + DefaultContent = defaultContent, + PageTransition = null, + Router = null + }; + + var root = new TestRoot + { + Child = host + }; + + Assert.NotNull(host.Content); + Assert.Equal(defaultContent, host.Content); + + host.Router = screen.Router; + + Assert.NotNull(host.Content); + Assert.Equal(defaultContent, host.Content); + + var first = new FirstRoutableViewModel(); + screen.Router.Navigate.Execute(first).Subscribe(); + + Assert.NotNull(host.Content); + Assert.Equal(typeof(FirstRoutableView), host.Content.GetType()); + Assert.Equal(first, ((FirstRoutableView)host.Content).DataContext); + Assert.Equal(first, ((FirstRoutableView)host.Content).ViewModel); + } } } \ No newline at end of file From b2b7fafabfc211cf37f227dc263ec40f20adeafe Mon Sep 17 00:00:00 2001 From: artyom Date: Mon, 10 Aug 2020 23:41:09 +0300 Subject: [PATCH 190/344] Bring additional tests for binding hooks --- .../AutoDataTemplateBindingHookTest.cs | 64 ++++++++++++++++--- 1 file changed, 54 insertions(+), 10 deletions(-) diff --git a/tests/Avalonia.ReactiveUI.UnitTests/AutoDataTemplateBindingHookTest.cs b/tests/Avalonia.ReactiveUI.UnitTests/AutoDataTemplateBindingHookTest.cs index 8ef37dbd21..2fdd12a391 100644 --- a/tests/Avalonia.ReactiveUI.UnitTests/AutoDataTemplateBindingHookTest.cs +++ b/tests/Avalonia.ReactiveUI.UnitTests/AutoDataTemplateBindingHookTest.cs @@ -28,11 +28,36 @@ namespace Avalonia.ReactiveUI.UnitTests public class ExampleView : ReactiveUserControl { - public ItemsControl List { get; } = new ItemsControl(); + public ItemsControl List { get; } = new ItemsControl + { + Template = GetTemplate() + }; public ExampleView() { + List.ApplyTemplate(); + List.Presenter.ApplyTemplate(); Content = List; + + ViewModel = new ExampleViewModel(); + this.OneWayBind(ViewModel, x => x.Items, x => x.List.Items); + } + } + + public class ExampleViewWithItemTemplate : ReactiveUserControl + { + public ItemsControl List { get; } = new ItemsControl + { + Template = GetTemplate() + }; + + public ExampleViewWithItemTemplate() + { + List.ApplyTemplate(); + List.Presenter.ApplyTemplate(); + List.ItemTemplate = GetItemTemplate(); + Content = List; + ViewModel = new ExampleViewModel(); this.OneWayBind(ViewModel, x => x.Items, x => x.List.Items); } @@ -50,6 +75,15 @@ namespace Avalonia.ReactiveUI.UnitTests { var view = new ExampleView(); Assert.NotNull(view.List.ItemTemplate); + Assert.IsType>(view.List.ItemTemplate); + } + + [Fact] + public void Should_Not_Override_Data_Template_Binding_When_Item_Template_Is_Set() + { + var view = new ExampleViewWithItemTemplate(); + Assert.NotNull(view.List.ItemTemplate); + Assert.IsType>(view.List.ItemTemplate); } [Fact] @@ -58,10 +92,6 @@ namespace Avalonia.ReactiveUI.UnitTests var view = new ExampleView(); view.ViewModel.Items.Add(new NestedViewModel()); - view.List.Template = GetTemplate(); - view.List.ApplyTemplate(); - view.List.Presenter.ApplyTemplate(); - var child = view.List.Presenter.Panel.Children[0]; var container = (ContentPresenter) child; container.UpdateChild(); @@ -69,6 +99,19 @@ namespace Avalonia.ReactiveUI.UnitTests Assert.IsType(container.Child); } + [Fact] + public void Should_Not_Use_View_Model_View_Host_When_Item_Template_Is_Set() + { + var view = new ExampleViewWithItemTemplate(); + view.ViewModel.Items.Add(new NestedViewModel()); + + var child = view.List.Presenter.Panel.Children[0]; + var container = (ContentPresenter) child; + container.UpdateChild(); + + Assert.IsType(container.Child); + } + [Fact] public void Should_Resolve_And_Embedd_Appropriate_View_Model() { @@ -76,10 +119,6 @@ namespace Avalonia.ReactiveUI.UnitTests var root = new TestRoot { Child = view }; view.ViewModel.Items.Add(new NestedViewModel()); - view.List.Template = GetTemplate(); - view.List.ApplyTemplate(); - view.List.Presenter.ApplyTemplate(); - var child = view.List.Presenter.Panel.Children[0]; var container = (ContentPresenter) child; container.UpdateChild(); @@ -93,7 +132,12 @@ namespace Avalonia.ReactiveUI.UnitTests Assert.IsType(host.DataContext); } - private FuncControlTemplate GetTemplate() + private static FuncDataTemplate GetItemTemplate() + { + return new FuncDataTemplate((parent, scope) => new TextBlock()); + } + + private static FuncControlTemplate GetTemplate() { return new FuncControlTemplate((parent, scope) => { From fbc549b51cfa62a45de0f5171dd9e9ada70e54b1 Mon Sep 17 00:00:00 2001 From: artyom Date: Mon, 10 Aug 2020 23:57:46 +0300 Subject: [PATCH 191/344] Don't apply hook when DataTemplates property is set --- .../AutoDataTemplateBindingHook.cs | 4 ++ .../AutoDataTemplateBindingHookTest.cs | 57 ++++++++----------- 2 files changed, 28 insertions(+), 33 deletions(-) diff --git a/src/Avalonia.ReactiveUI/AutoDataTemplateBindingHook.cs b/src/Avalonia.ReactiveUI/AutoDataTemplateBindingHook.cs index 4881c77034..fe4e9dd94a 100644 --- a/src/Avalonia.ReactiveUI/AutoDataTemplateBindingHook.cs +++ b/src/Avalonia.ReactiveUI/AutoDataTemplateBindingHook.cs @@ -48,6 +48,10 @@ namespace Avalonia.ReactiveUI if (itemsControl.ItemTemplate != null) return true; + if (itemsControl.DataTemplates != null && + itemsControl.DataTemplates.Count > 0) + return true; + itemsControl.ItemTemplate = DefaultItemTemplate; return true; } diff --git a/tests/Avalonia.ReactiveUI.UnitTests/AutoDataTemplateBindingHookTest.cs b/tests/Avalonia.ReactiveUI.UnitTests/AutoDataTemplateBindingHookTest.cs index 2fdd12a391..0a04d802e2 100644 --- a/tests/Avalonia.ReactiveUI.UnitTests/AutoDataTemplateBindingHookTest.cs +++ b/tests/Avalonia.ReactiveUI.UnitTests/AutoDataTemplateBindingHookTest.cs @@ -33,31 +33,13 @@ namespace Avalonia.ReactiveUI.UnitTests Template = GetTemplate() }; - public ExampleView() + public ExampleView(Action adjustItemsControl = null) { + adjustItemsControl?.Invoke(List); List.ApplyTemplate(); List.Presenter.ApplyTemplate(); + Content = List; - - ViewModel = new ExampleViewModel(); - this.OneWayBind(ViewModel, x => x.Items, x => x.List.Items); - } - } - - public class ExampleViewWithItemTemplate : ReactiveUserControl - { - public ItemsControl List { get; } = new ItemsControl - { - Template = GetTemplate() - }; - - public ExampleViewWithItemTemplate() - { - List.ApplyTemplate(); - List.Presenter.ApplyTemplate(); - List.ItemTemplate = GetItemTemplate(); - Content = List; - ViewModel = new ExampleViewModel(); this.OneWayBind(ViewModel, x => x.Items, x => x.List.Items); } @@ -81,7 +63,7 @@ namespace Avalonia.ReactiveUI.UnitTests [Fact] public void Should_Not_Override_Data_Template_Binding_When_Item_Template_Is_Set() { - var view = new ExampleViewWithItemTemplate(); + var view = new ExampleView(control => control.ItemTemplate = GetItemTemplate()); Assert.NotNull(view.List.ItemTemplate); Assert.IsType>(view.List.ItemTemplate); } @@ -102,7 +84,20 @@ namespace Avalonia.ReactiveUI.UnitTests [Fact] public void Should_Not_Use_View_Model_View_Host_When_Item_Template_Is_Set() { - var view = new ExampleViewWithItemTemplate(); + var view = new ExampleView(control => control.ItemTemplate = GetItemTemplate()); + view.ViewModel.Items.Add(new NestedViewModel()); + + var child = view.List.Presenter.Panel.Children[0]; + var container = (ContentPresenter) child; + container.UpdateChild(); + + Assert.IsType(container.Child); + } + + [Fact] + public void Should_Not_Use_View_Model_View_Host_When_Data_Templates_Are_Not_Empty() + { + var view = new ExampleView(control => control.DataTemplates.Add(GetItemTemplate())); view.ViewModel.Items.Add(new NestedViewModel()); var child = view.List.Presenter.Panel.Children[0]; @@ -116,7 +111,6 @@ namespace Avalonia.ReactiveUI.UnitTests public void Should_Resolve_And_Embedd_Appropriate_View_Model() { var view = new ExampleView(); - var root = new TestRoot { Child = view }; view.ViewModel.Items.Add(new NestedViewModel()); var child = view.List.Presenter.Panel.Children[0]; @@ -139,17 +133,14 @@ namespace Avalonia.ReactiveUI.UnitTests private static FuncControlTemplate GetTemplate() { - return new FuncControlTemplate((parent, scope) => + return new FuncControlTemplate((parent, scope) => new Border { - return new Border + Background = new Media.SolidColorBrush(0xffffffff), + Child = new ItemsPresenter { - Background = new Media.SolidColorBrush(0xffffffff), - Child = new ItemsPresenter - { - Name = "PART_ItemsPresenter", - [~ItemsPresenter.ItemsProperty] = parent[~ItemsControl.ItemsProperty], - }.RegisterInNameScope(scope) - }; + Name = "PART_ItemsPresenter", + [~ItemsPresenter.ItemsProperty] = parent[~ItemsControl.ItemsProperty], + }.RegisterInNameScope(scope) }); } } From 0bbe03643744a9a1563da82e55a290fea4449a21 Mon Sep 17 00:00:00 2001 From: artyom Date: Tue, 11 Aug 2020 10:35:29 +0300 Subject: [PATCH 192/344] Show DefaultContent when Router is set to null --- src/Avalonia.ReactiveUI/RoutedViewHost.cs | 12 +++-- .../AutoDataTemplateBindingHookTest.cs | 50 ++++++++--------- .../RoutedViewHostTest.cs | 54 +++++++++---------- 3 files changed, 61 insertions(+), 55 deletions(-) diff --git a/src/Avalonia.ReactiveUI/RoutedViewHost.cs b/src/Avalonia.ReactiveUI/RoutedViewHost.cs index 5520121033..38100f4829 100644 --- a/src/Avalonia.ReactiveUI/RoutedViewHost.cs +++ b/src/Avalonia.ReactiveUI/RoutedViewHost.cs @@ -65,9 +65,15 @@ namespace Avalonia.ReactiveUI { this.WhenActivated(disposables => { - this.WhenAnyObservable(x => x.Router.CurrentViewModel) - .StartWith(default(object)) - .DistinctUntilChanged() + var routerRemoved = this + .WhenAnyValue(x => x.Router) + .Where(router => router == null) + .Cast(); + + this.WhenAnyValue(x => x.Router) + .Where(router => router != null) + .SelectMany(router => router.CurrentViewModel) + .Merge(routerRemoved) .Subscribe(NavigateToViewModel) .DisposeWith(disposables); }); diff --git a/tests/Avalonia.ReactiveUI.UnitTests/AutoDataTemplateBindingHookTest.cs b/tests/Avalonia.ReactiveUI.UnitTests/AutoDataTemplateBindingHookTest.cs index 0a04d802e2..53bdff5dff 100644 --- a/tests/Avalonia.ReactiveUI.UnitTests/AutoDataTemplateBindingHookTest.cs +++ b/tests/Avalonia.ReactiveUI.UnitTests/AutoDataTemplateBindingHookTest.cs @@ -61,15 +61,7 @@ namespace Avalonia.ReactiveUI.UnitTests } [Fact] - public void Should_Not_Override_Data_Template_Binding_When_Item_Template_Is_Set() - { - var view = new ExampleView(control => control.ItemTemplate = GetItemTemplate()); - Assert.NotNull(view.List.ItemTemplate); - Assert.IsType>(view.List.ItemTemplate); - } - - [Fact] - public void Should_Use_View_Model_View_Host_As_Data_Template() + public void Should_Use_ViewModelViewHost_As_Data_Template_By_Default() { var view = new ExampleView(); view.ViewModel.Items.Add(new NestedViewModel()); @@ -82,22 +74,36 @@ namespace Avalonia.ReactiveUI.UnitTests } [Fact] - public void Should_Not_Use_View_Model_View_Host_When_Item_Template_Is_Set() + public void ViewModelViewHost_Should_Resolve_And_Embedd_Appropriate_View_Model() { - var view = new ExampleView(control => control.ItemTemplate = GetItemTemplate()); + var view = new ExampleView(); view.ViewModel.Items.Add(new NestedViewModel()); var child = view.List.Presenter.Panel.Children[0]; var container = (ContentPresenter) child; container.UpdateChild(); - Assert.IsType(container.Child); + var host = (ViewModelViewHost) container.Child; + Assert.IsType(host.ViewModel); + Assert.IsType(host.DataContext); + + host.DataContext = "changed context"; + Assert.IsType(host.ViewModel); + Assert.IsType(host.DataContext); } - + [Fact] - public void Should_Not_Use_View_Model_View_Host_When_Data_Templates_Are_Not_Empty() + public void Should_Not_Override_Data_Template_Binding_When_Item_Template_Is_Set() { - var view = new ExampleView(control => control.DataTemplates.Add(GetItemTemplate())); + var view = new ExampleView(control => control.ItemTemplate = GetItemTemplate()); + Assert.NotNull(view.List.ItemTemplate); + Assert.IsType>(view.List.ItemTemplate); + } + + [Fact] + public void Should_Not_Use_View_Model_View_Host_When_Item_Template_Is_Set() + { + var view = new ExampleView(control => control.ItemTemplate = GetItemTemplate()); view.ViewModel.Items.Add(new NestedViewModel()); var child = view.List.Presenter.Panel.Children[0]; @@ -106,24 +112,18 @@ namespace Avalonia.ReactiveUI.UnitTests Assert.IsType(container.Child); } - + [Fact] - public void Should_Resolve_And_Embedd_Appropriate_View_Model() + public void Should_Not_Use_View_Model_View_Host_When_Data_Templates_Are_Not_Empty() { - var view = new ExampleView(); + var view = new ExampleView(control => control.DataTemplates.Add(GetItemTemplate())); view.ViewModel.Items.Add(new NestedViewModel()); var child = view.List.Presenter.Panel.Children[0]; var container = (ContentPresenter) child; container.UpdateChild(); - var host = (ViewModelViewHost) container.Child; - Assert.IsType(host.ViewModel); - Assert.IsType(host.DataContext); - - host.DataContext = "changed context"; - Assert.IsType(host.ViewModel); - Assert.IsType(host.DataContext); + Assert.IsType(container.Child); } private static FuncDataTemplate GetItemTemplate() diff --git a/tests/Avalonia.ReactiveUI.UnitTests/RoutedViewHostTest.cs b/tests/Avalonia.ReactiveUI.UnitTests/RoutedViewHostTest.cs index 5b7f7fe336..b82b1b1acc 100644 --- a/tests/Avalonia.ReactiveUI.UnitTests/RoutedViewHostTest.cs +++ b/tests/Avalonia.ReactiveUI.UnitTests/RoutedViewHostTest.cs @@ -62,50 +62,42 @@ namespace Avalonia.ReactiveUI.UnitTests PageTransition = null }; - var root = new TestRoot - { - Child = host + var root = new TestRoot + { + Child = host }; Assert.NotNull(host.Content); - Assert.Equal(typeof(TextBlock), host.Content.GetType()); + Assert.IsType(host.Content); Assert.Equal(defaultContent, host.Content); var first = new FirstRoutableViewModel(); - screen.Router.Navigate - .Execute(first) - .Subscribe(); + screen.Router.Navigate.Execute(first).Subscribe(); Assert.NotNull(host.Content); - Assert.Equal(typeof(FirstRoutableView), host.Content.GetType()); + Assert.IsType(host.Content); Assert.Equal(first, ((FirstRoutableView)host.Content).DataContext); Assert.Equal(first, ((FirstRoutableView)host.Content).ViewModel); var second = new SecondRoutableViewModel(); - screen.Router.Navigate - .Execute(second) - .Subscribe(); + screen.Router.Navigate.Execute(second).Subscribe(); Assert.NotNull(host.Content); - Assert.Equal(typeof(SecondRoutableView), host.Content.GetType()); + Assert.IsType(host.Content); Assert.Equal(second, ((SecondRoutableView)host.Content).DataContext); Assert.Equal(second, ((SecondRoutableView)host.Content).ViewModel); - screen.Router.NavigateBack - .Execute(Unit.Default) - .Subscribe(); + screen.Router.NavigateBack.Execute(Unit.Default).Subscribe(); Assert.NotNull(host.Content); - Assert.Equal(typeof(FirstRoutableView), host.Content.GetType()); + Assert.IsType(host.Content); Assert.Equal(first, ((FirstRoutableView)host.Content).DataContext); Assert.Equal(first, ((FirstRoutableView)host.Content).ViewModel); - screen.Router.NavigateBack - .Execute(Unit.Default) - .Subscribe(); + screen.Router.NavigateBack.Execute(Unit.Default).Subscribe(); Assert.NotNull(host.Content); - Assert.Equal(typeof(TextBlock), host.Content.GetType()); + Assert.IsType(host.Content); Assert.Equal(defaultContent, host.Content); } @@ -121,9 +113,9 @@ namespace Avalonia.ReactiveUI.UnitTests Router = null }; - var root = new TestRoot - { - Child = host + var root = new TestRoot + { + Child = host }; Assert.NotNull(host.Content); @@ -138,9 +130,17 @@ namespace Avalonia.ReactiveUI.UnitTests screen.Router.Navigate.Execute(first).Subscribe(); Assert.NotNull(host.Content); - Assert.Equal(typeof(FirstRoutableView), host.Content.GetType()); - Assert.Equal(first, ((FirstRoutableView)host.Content).DataContext); - Assert.Equal(first, ((FirstRoutableView)host.Content).ViewModel); + Assert.IsType(host.Content); + + host.Router = null; + + Assert.NotNull(host.Content); + Assert.Equal(defaultContent, host.Content); + + host.Router = screen.Router; + + Assert.NotNull(host.Content); + Assert.IsType(host.Content); } } -} \ No newline at end of file +} From 64d11e2e316e4d4a402e26bb846aff1c6ee17e45 Mon Sep 17 00:00:00 2001 From: artyom Date: Tue, 11 Aug 2020 10:37:20 +0300 Subject: [PATCH 193/344] Cast the view to IDataContextProvider --- src/Avalonia.ReactiveUI/RoutedViewHost.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.ReactiveUI/RoutedViewHost.cs b/src/Avalonia.ReactiveUI/RoutedViewHost.cs index 38100f4829..421633cd58 100644 --- a/src/Avalonia.ReactiveUI/RoutedViewHost.cs +++ b/src/Avalonia.ReactiveUI/RoutedViewHost.cs @@ -124,8 +124,8 @@ namespace Avalonia.ReactiveUI this.Log().Info($"Ready to show {viewInstance} with autowired {viewModel}."); viewInstance.ViewModel = viewModel; - if (viewInstance is IStyledElement styled) - styled.DataContext = viewModel; + if (viewInstance is IDataContextProvider provider) + provider.DataContext = viewModel; Content = viewInstance; } } From d59a0f80fe09ce670d78a6a06a7bc674f8a45829 Mon Sep 17 00:00:00 2001 From: artyom Date: Tue, 11 Aug 2020 10:40:41 +0300 Subject: [PATCH 194/344] Use latest ReactiveUI --- build/ReactiveUI.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/ReactiveUI.props b/build/ReactiveUI.props index f827cb9a32..d8e86e917e 100644 --- a/build/ReactiveUI.props +++ b/build/ReactiveUI.props @@ -1,5 +1,5 @@ - + From d5716fce8f24aeebad0485b45abe4dedeb3ee53d Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Tue, 11 Aug 2020 15:30:36 +0200 Subject: [PATCH 195/344] Added failing data validation test. --- .../AvaloniaObjectTests_DataValidation.cs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_DataValidation.cs b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_DataValidation.cs index e8cc71c723..65f03b3eca 100644 --- a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_DataValidation.cs +++ b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_DataValidation.cs @@ -62,6 +62,20 @@ namespace Avalonia.Base.UnitTests Assert.Equal(7, result[3].Value); } + [Fact] + public void Binding_Overridden_Validated_Direct_Property_Calls_UpdateDataValidation() + { + var target = new Class2(); + var source = new Subject>(); + + // Class2 overrides `NonValidatedDirectProperty`'s metadata to enable data validation. + target.Bind(Class1.NonValidatedDirectProperty, source); + source.OnNext(1); + + var result = target.Notifications.Cast>().ToList(); + Assert.Equal(1, result.Count); + } + [Fact] public void Bound_Validated_Direct_String_Property_Can_Be_Set_To_Null() { @@ -150,6 +164,15 @@ namespace Avalonia.Base.UnitTests } } + private class Class2 : Class1 + { + static Class2() + { + NonValidatedDirectProperty.OverrideMetadata( + new DirectPropertyMetadata(enableDataValidation: true)); + } + } + public class ViewModel : NotifyingBase { private string _stringValue; From 37bd384794174e273ffd8706b1c157792bc0607c Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Tue, 11 Aug 2020 15:39:23 +0200 Subject: [PATCH 196/344] Use EnabledDataValidation from metadata. `DirectProperty` stored a `EnabledDataValidation` flag in its metadata but also had an `IsDataValidationEnabled` property in `DirectPropertyBase` which was the one used by `AvaloniaObject`. Use the version from metadata so that it can be overridden and remove the flag from `DirectPropertyBase`. --- src/Avalonia.Base/AvaloniaObject.cs | 4 ++- src/Avalonia.Base/AvaloniaProperty.cs | 6 ++--- src/Avalonia.Base/DirectProperty.cs | 25 ++++++------------- src/Avalonia.Base/DirectPropertyBase.cs | 19 ++------------ .../AvaloniaObjectTests_Direct.cs | 6 ++--- .../DirectPropertyTests.cs | 3 +-- 6 files changed, 19 insertions(+), 44 deletions(-) diff --git a/src/Avalonia.Base/AvaloniaObject.cs b/src/Avalonia.Base/AvaloniaObject.cs index d18f0b3f94..65233f9230 100644 --- a/src/Avalonia.Base/AvaloniaObject.cs +++ b/src/Avalonia.Base/AvaloniaObject.cs @@ -806,7 +806,9 @@ namespace Avalonia break; } - if (p.IsDataValidationEnabled) + var metadata = p.GetMetadata(GetType()); + + if (metadata.EnableDataValidation == true) { UpdateDataValidation(property, value); } diff --git a/src/Avalonia.Base/AvaloniaProperty.cs b/src/Avalonia.Base/AvaloniaProperty.cs index a873d5fd42..39391490b0 100644 --- a/src/Avalonia.Base/AvaloniaProperty.cs +++ b/src/Avalonia.Base/AvaloniaProperty.cs @@ -369,14 +369,14 @@ namespace Avalonia var metadata = new DirectPropertyMetadata( unsetValue: unsetValue, - defaultBindingMode: defaultBindingMode); + defaultBindingMode: defaultBindingMode, + enableDataValidation: enableDataValidation); var result = new DirectProperty( name, getter, setter, - metadata, - enableDataValidation); + metadata); AvaloniaPropertyRegistry.Instance.Register(typeof(TOwner), result); return result; } diff --git a/src/Avalonia.Base/DirectProperty.cs b/src/Avalonia.Base/DirectProperty.cs index d21969502a..a8120fbd4f 100644 --- a/src/Avalonia.Base/DirectProperty.cs +++ b/src/Avalonia.Base/DirectProperty.cs @@ -23,16 +23,12 @@ namespace Avalonia /// Gets the current value of the property. /// Sets the value of the property. May be null. /// The property metadata. - /// - /// Whether the property is interested in data validation. - /// public DirectProperty( string name, Func getter, Action setter, - DirectPropertyMetadata metadata, - bool enableDataValidation) - : base(name, typeof(TOwner), metadata, enableDataValidation) + DirectPropertyMetadata metadata) + : base(name, typeof(TOwner), metadata) { Contract.Requires(getter != null); @@ -47,16 +43,12 @@ namespace Avalonia /// Gets the current value of the property. /// Sets the value of the property. May be null. /// Optional overridden metadata. - /// - /// Whether the property is interested in data validation. - /// private DirectProperty( DirectPropertyBase source, Func getter, Action setter, - DirectPropertyMetadata metadata, - bool enableDataValidation) - : base(source, typeof(TOwner), metadata, enableDataValidation) + DirectPropertyMetadata metadata) + : base(source, typeof(TOwner), metadata) { Contract.Requires(getter != null); @@ -107,7 +99,8 @@ namespace Avalonia { var metadata = new DirectPropertyMetadata( unsetValue: unsetValue, - defaultBindingMode: defaultBindingMode); + defaultBindingMode: defaultBindingMode, + enableDataValidation: enableDataValidation); metadata.Merge(GetMetadata(), this); @@ -115,8 +108,7 @@ namespace Avalonia (DirectPropertyBase)this, getter, setter, - metadata, - enableDataValidation); + metadata); AvaloniaPropertyRegistry.Instance.Register(typeof(TNewOwner), result); return result; @@ -155,8 +147,7 @@ namespace Avalonia this, getter, setter, - metadata, - enableDataValidation); + metadata); AvaloniaPropertyRegistry.Instance.Register(typeof(TNewOwner), result); return result; diff --git a/src/Avalonia.Base/DirectPropertyBase.cs b/src/Avalonia.Base/DirectPropertyBase.cs index 334b90177b..dbc2625b86 100644 --- a/src/Avalonia.Base/DirectPropertyBase.cs +++ b/src/Avalonia.Base/DirectPropertyBase.cs @@ -23,17 +23,12 @@ namespace Avalonia /// The name of the property. /// The type of the class that registers the property. /// The property metadata. - /// - /// Whether the property is interested in data validation. - /// protected DirectPropertyBase( string name, Type ownerType, - PropertyMetadata metadata, - bool enableDataValidation) + PropertyMetadata metadata) : base(name, ownerType, metadata) { - IsDataValidationEnabled = enableDataValidation; } /// @@ -42,17 +37,12 @@ namespace Avalonia /// The property to copy. /// The new owner type. /// Optional overridden metadata. - /// - /// Whether the property is interested in data validation. - /// protected DirectPropertyBase( AvaloniaProperty source, Type ownerType, - PropertyMetadata metadata, - bool enableDataValidation) + PropertyMetadata metadata) : base(source, ownerType, metadata) { - IsDataValidationEnabled = enableDataValidation; } /// @@ -60,11 +50,6 @@ namespace Avalonia /// public abstract Type Owner { get; } - /// - /// Gets a value that indicates whether data validation is enabled for the property. - /// - public bool IsDataValidationEnabled { get; } - /// /// Gets the value of the property on the instance. /// diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Direct.cs b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Direct.cs index 60d06b359a..81a8de1046 100644 --- a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Direct.cs +++ b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Direct.cs @@ -547,8 +547,7 @@ namespace Avalonia.Base.UnitTests "foo", o => "foo", null, - new DirectPropertyMetadata(defaultBindingMode: BindingMode.TwoWay), - false); + new DirectPropertyMetadata(defaultBindingMode: BindingMode.TwoWay)); var bar = foo.AddOwner(o => "bar"); Assert.Equal(BindingMode.TwoWay, bar.GetMetadata().DefaultBindingMode); @@ -562,8 +561,7 @@ namespace Avalonia.Base.UnitTests "foo", o => "foo", null, - new DirectPropertyMetadata(defaultBindingMode: BindingMode.TwoWay), - false); + new DirectPropertyMetadata(defaultBindingMode: BindingMode.TwoWay)); var bar = foo.AddOwner(o => "bar", defaultBindingMode: BindingMode.OneWayToSource); Assert.Equal(BindingMode.TwoWay, bar.GetMetadata().DefaultBindingMode); diff --git a/tests/Avalonia.Base.UnitTests/DirectPropertyTests.cs b/tests/Avalonia.Base.UnitTests/DirectPropertyTests.cs index 08b62ae100..e7e3b5764f 100644 --- a/tests/Avalonia.Base.UnitTests/DirectPropertyTests.cs +++ b/tests/Avalonia.Base.UnitTests/DirectPropertyTests.cs @@ -11,8 +11,7 @@ namespace Avalonia.Base.UnitTests "test", o => null, null, - new DirectPropertyMetadata(), - false); + new DirectPropertyMetadata()); Assert.True(target.IsDirect); } From edd20a414172c3a6318fa7b8a8b3ffe35daa6939 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Tue, 11 Aug 2020 15:42:07 +0200 Subject: [PATCH 197/344] Added API changes to ApiCompatBaseline. --- src/Avalonia.Base/ApiCompatBaseline.txt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/Avalonia.Base/ApiCompatBaseline.txt diff --git a/src/Avalonia.Base/ApiCompatBaseline.txt b/src/Avalonia.Base/ApiCompatBaseline.txt new file mode 100644 index 0000000000..b0b7371cd7 --- /dev/null +++ b/src/Avalonia.Base/ApiCompatBaseline.txt @@ -0,0 +1,6 @@ +Compat issues with assembly Avalonia.Base: +MembersMustExist : Member 'public void Avalonia.DirectProperty..ctor(System.String, System.Func, System.Action, Avalonia.DirectPropertyMetadata, System.Boolean)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'protected void Avalonia.DirectPropertyBase..ctor(Avalonia.AvaloniaProperty, System.Type, Avalonia.PropertyMetadata, System.Boolean)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'protected void Avalonia.DirectPropertyBase..ctor(System.String, System.Type, Avalonia.PropertyMetadata, System.Boolean)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Boolean Avalonia.DirectPropertyBase.IsDataValidationEnabled.get()' does not exist in the implementation but it does exist in the contract. +Total Issues: 4 From ffa8fa7262ebc13672dd926656a6ca16e5cd5fd2 Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Wed, 12 Aug 2020 20:31:06 +0800 Subject: [PATCH 198/344] implement ShowPassword Property in textpresenter and forward from textbox --- samples/ControlCatalog/Pages/TextBoxPage.xaml | 2 +- .../Presenters/TextPresenter.cs | 15 +++++++++++--- src/Avalonia.Controls/TextBox.cs | 20 ++++++------------- src/Avalonia.Themes.Fluent/TextBox.xaml | 10 +++++++++- 4 files changed, 28 insertions(+), 19 deletions(-) diff --git a/samples/ControlCatalog/Pages/TextBoxPage.xaml b/samples/ControlCatalog/Pages/TextBoxPage.xaml index cae3d20169..55231363d2 100644 --- a/samples/ControlCatalog/Pages/TextBoxPage.xaml +++ b/samples/ControlCatalog/Pages/TextBoxPage.xaml @@ -36,7 +36,7 @@ - + diff --git a/src/Avalonia.Controls/Presenters/TextPresenter.cs b/src/Avalonia.Controls/Presenters/TextPresenter.cs index 6e534bbb2a..ef33ac19f6 100644 --- a/src/Avalonia.Controls/Presenters/TextPresenter.cs +++ b/src/Avalonia.Controls/Presenters/TextPresenter.cs @@ -14,6 +14,9 @@ namespace Avalonia.Controls.Presenters o => o.CaretIndex, (o, v) => o.CaretIndex = v); + public static readonly StyledProperty ShowPasswordCharProperty = + AvaloniaProperty.Register(nameof(ShowPasswordChar), true); + public static readonly StyledProperty PasswordCharProperty = AvaloniaProperty.Register(nameof(PasswordChar)); @@ -75,7 +78,7 @@ namespace Avalonia.Controls.Presenters static TextPresenter() { AffectsRender(SelectionBrushProperty); - AffectsMeasure(TextProperty, PasswordCharProperty, + AffectsMeasure(TextProperty, PasswordCharProperty, ShowPasswordCharProperty, TextAlignmentProperty, TextWrappingProperty, TextBlock.FontSizeProperty, TextBlock.FontStyleProperty, TextBlock.FontWeightProperty, TextBlock.FontFamilyProperty); @@ -84,7 +87,7 @@ namespace Avalonia.Controls.Presenters TextBlock.FontSizeProperty.Changed, TextBlock.FontStyleProperty.Changed, TextBlock.FontWeightProperty.Changed, TextBlock.FontFamilyProperty.Changed, SelectionStartProperty.Changed, SelectionEndProperty.Changed, - SelectionForegroundBrushProperty.Changed, PasswordCharProperty.Changed + SelectionForegroundBrushProperty.Changed, PasswordCharProperty.Changed, ShowPasswordCharProperty.Changed ).AddClassHandler((x, _) => x.InvalidateFormattedText()); CaretIndexProperty.Changed.AddClassHandler((x, e) => x.CaretIndexChanged((int)e.NewValue)); @@ -210,6 +213,12 @@ namespace Avalonia.Controls.Presenters set => SetValue(PasswordCharProperty, value); } + public bool ShowPasswordChar + { + get => GetValue(ShowPasswordCharProperty); + set => SetValue(ShowPasswordCharProperty, value); + } + public IBrush SelectionBrush { get => GetValue(SelectionBrushProperty); @@ -426,7 +435,7 @@ namespace Avalonia.Controls.Presenters var text = Text; - if (PasswordChar != default(char)) + if (PasswordChar != default(char) && ShowPasswordChar) { result = CreateFormattedTextInternal(_constraint, new string(PasswordChar, text?.Length ?? 0)); } diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index 23728d7997..08e4e923f5 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -101,8 +101,8 @@ namespace Avalonia.Controls public static readonly StyledProperty InnerRightContentProperty = AvaloniaProperty.Register(nameof(InnerRightContent)); - public static readonly StyledProperty ShowPasswordProperty = - AvaloniaProperty.Register(nameof(ShowPassword)); + public static readonly StyledProperty ShowPasswordCharProperty = + AvaloniaProperty.Register(nameof(ShowPasswordChar)); struct UndoRedoState : IEquatable { @@ -132,10 +132,6 @@ namespace Avalonia.Controls static TextBox() { FocusableProperty.OverrideDefaultValue(typeof(TextBox), true); - ShowPasswordProperty.Changed.Subscribe((x)=> - { - - }); } public TextBox() @@ -351,14 +347,10 @@ namespace Avalonia.Controls set { SetValue(InnerRightContentProperty, value); } } - public bool ShowPassword + public bool ShowPasswordChar { - get { return GetValue(ShowPasswordProperty); } - set - { - - SetValue(ShowPasswordProperty, value); - } + get { return GetValue(ShowPasswordCharProperty); } + set { SetValue(ShowPasswordCharProperty, value); } } public TextWrapping TextWrapping @@ -1108,7 +1100,7 @@ namespace Avalonia.Controls SelectionEnd = CaretIndex; } - private bool IsPasswordBox => ShowPassword && PasswordChar != default(char); + private bool IsPasswordBox => PasswordChar != default(char); UndoRedoState UndoRedoHelper.IUndoRedoHost.UndoRedoState { diff --git a/src/Avalonia.Themes.Fluent/TextBox.xaml b/src/Avalonia.Themes.Fluent/TextBox.xaml index 5278e5d3d0..0735b83014 100644 --- a/src/Avalonia.Themes.Fluent/TextBox.xaml +++ b/src/Avalonia.Themes.Fluent/TextBox.xaml @@ -79,6 +79,7 @@ TextAlignment="{TemplateBinding TextAlignment}" TextWrapping="{TemplateBinding TextWrapping}" PasswordChar="{TemplateBinding PasswordChar}" + ShowPasswordChar="{TemplateBinding ShowPasswordChar}" SelectionBrush="{TemplateBinding SelectionBrush}" SelectionForegroundBrush="{TemplateBinding SelectionForegroundBrush}" CaretBrush="{TemplateBinding CaretBrush}" @@ -142,7 +143,6 @@ - @@ -151,4 +151,12 @@ + + From e8d3ad9d3f381c54383a0a532038e0440f868030 Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Wed, 12 Aug 2020 20:40:30 +0800 Subject: [PATCH 199/344] revert unnecessary changes --- samples/ControlCatalog/Pages/TextBoxPage.xaml | 77 ++++++++++--------- 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/samples/ControlCatalog/Pages/TextBoxPage.xaml b/samples/ControlCatalog/Pages/TextBoxPage.xaml index 55231363d2..8dc947c298 100644 --- a/samples/ControlCatalog/Pages/TextBoxPage.xaml +++ b/samples/ControlCatalog/Pages/TextBoxPage.xaml @@ -1,7 +1,7 @@ + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + x:Class="ControlCatalog.Pages.TextBoxPage"> - - + - TextBox A control into which the user can input text - + - + - - + - + - - + + + - - resm fonts - - - - - - - - res fonts - - - - + + resm fonts + + + + + + + + res fonts + + + + + - - - - From 661480e55c957295aebdabd7374ae197dae6a6d4 Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Wed, 12 Aug 2020 20:59:01 +0800 Subject: [PATCH 200/344] polish --- samples/ControlCatalog/Pages/TextBoxPage.xaml | 21 ++--------- .../Presenters/TextPresenter.cs | 16 ++++---- src/Avalonia.Controls/TextBox.cs | 10 ++--- src/Avalonia.Themes.Fluent/TextBox.xaml | 37 +++++++++++++++++-- 4 files changed, 49 insertions(+), 35 deletions(-) diff --git a/samples/ControlCatalog/Pages/TextBoxPage.xaml b/samples/ControlCatalog/Pages/TextBoxPage.xaml index 8dc947c298..256212eaf1 100644 --- a/samples/ControlCatalog/Pages/TextBoxPage.xaml +++ b/samples/ControlCatalog/Pages/TextBoxPage.xaml @@ -2,22 +2,6 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="ControlCatalog.Pages.TextBoxPage"> - - - - TextBox A control into which the user can input text @@ -36,6 +20,7 @@ @@ -54,8 +39,8 @@ - - + + resm fonts diff --git a/src/Avalonia.Controls/Presenters/TextPresenter.cs b/src/Avalonia.Controls/Presenters/TextPresenter.cs index ef33ac19f6..1cd7e11564 100644 --- a/src/Avalonia.Controls/Presenters/TextPresenter.cs +++ b/src/Avalonia.Controls/Presenters/TextPresenter.cs @@ -14,8 +14,8 @@ namespace Avalonia.Controls.Presenters o => o.CaretIndex, (o, v) => o.CaretIndex = v); - public static readonly StyledProperty ShowPasswordCharProperty = - AvaloniaProperty.Register(nameof(ShowPasswordChar), true); + public static readonly StyledProperty ShowPasswordTextProperty = + AvaloniaProperty.Register(nameof(ShowPasswordText)); public static readonly StyledProperty PasswordCharProperty = AvaloniaProperty.Register(nameof(PasswordChar)); @@ -78,7 +78,7 @@ namespace Avalonia.Controls.Presenters static TextPresenter() { AffectsRender(SelectionBrushProperty); - AffectsMeasure(TextProperty, PasswordCharProperty, ShowPasswordCharProperty, + AffectsMeasure(TextProperty, PasswordCharProperty, ShowPasswordTextProperty, TextAlignmentProperty, TextWrappingProperty, TextBlock.FontSizeProperty, TextBlock.FontStyleProperty, TextBlock.FontWeightProperty, TextBlock.FontFamilyProperty); @@ -87,7 +87,7 @@ namespace Avalonia.Controls.Presenters TextBlock.FontSizeProperty.Changed, TextBlock.FontStyleProperty.Changed, TextBlock.FontWeightProperty.Changed, TextBlock.FontFamilyProperty.Changed, SelectionStartProperty.Changed, SelectionEndProperty.Changed, - SelectionForegroundBrushProperty.Changed, PasswordCharProperty.Changed, ShowPasswordCharProperty.Changed + SelectionForegroundBrushProperty.Changed, PasswordCharProperty.Changed, ShowPasswordTextProperty.Changed ).AddClassHandler((x, _) => x.InvalidateFormattedText()); CaretIndexProperty.Changed.AddClassHandler((x, e) => x.CaretIndexChanged((int)e.NewValue)); @@ -213,10 +213,10 @@ namespace Avalonia.Controls.Presenters set => SetValue(PasswordCharProperty, value); } - public bool ShowPasswordChar + public bool ShowPasswordText { - get => GetValue(ShowPasswordCharProperty); - set => SetValue(ShowPasswordCharProperty, value); + get => GetValue(ShowPasswordTextProperty); + set => SetValue(ShowPasswordTextProperty, value); } public IBrush SelectionBrush @@ -435,7 +435,7 @@ namespace Avalonia.Controls.Presenters var text = Text; - if (PasswordChar != default(char) && ShowPasswordChar) + if (PasswordChar != default(char) && !ShowPasswordText) { result = CreateFormattedTextInternal(_constraint, new string(PasswordChar, text?.Length ?? 0)); } diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index 08e4e923f5..489937147f 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -101,8 +101,8 @@ namespace Avalonia.Controls public static readonly StyledProperty InnerRightContentProperty = AvaloniaProperty.Register(nameof(InnerRightContent)); - public static readonly StyledProperty ShowPasswordCharProperty = - AvaloniaProperty.Register(nameof(ShowPasswordChar)); + public static readonly StyledProperty ShowPasswordTextProperty = + AvaloniaProperty.Register(nameof(ShowPasswordText)); struct UndoRedoState : IEquatable { @@ -347,10 +347,10 @@ namespace Avalonia.Controls set { SetValue(InnerRightContentProperty, value); } } - public bool ShowPasswordChar + public bool ShowPasswordText { - get { return GetValue(ShowPasswordCharProperty); } - set { SetValue(ShowPasswordCharProperty, value); } + get { return GetValue(ShowPasswordTextProperty); } + set { SetValue(ShowPasswordTextProperty, value); } } public TextWrapping TextWrapping diff --git a/src/Avalonia.Themes.Fluent/TextBox.xaml b/src/Avalonia.Themes.Fluent/TextBox.xaml index 0735b83014..3b66e7f09e 100644 --- a/src/Avalonia.Themes.Fluent/TextBox.xaml +++ b/src/Avalonia.Themes.Fluent/TextBox.xaml @@ -1,6 +1,14 @@ 0,0,0,4 + + + + + + + + - + + + + + From 2a11f6801ca791152f4d910288cd25a7d5a221df Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Wed, 12 Aug 2020 21:35:59 +0800 Subject: [PATCH 201/344] address review --- samples/ControlCatalog/Pages/TextBoxPage.xaml | 5 ++-- .../Presenters/TextPresenter.cs | 16 ++++++------- src/Avalonia.Controls/TextBox.cs | 10 ++++---- src/Avalonia.Themes.Fluent/TextBox.xaml | 24 +++++++------------ 4 files changed, 23 insertions(+), 32 deletions(-) diff --git a/samples/ControlCatalog/Pages/TextBoxPage.xaml b/samples/ControlCatalog/Pages/TextBoxPage.xaml index 256212eaf1..099d40b3de 100644 --- a/samples/ControlCatalog/Pages/TextBoxPage.xaml +++ b/samples/ControlCatalog/Pages/TextBoxPage.xaml @@ -20,7 +20,7 @@ @@ -39,8 +39,7 @@ - - + resm fonts diff --git a/src/Avalonia.Controls/Presenters/TextPresenter.cs b/src/Avalonia.Controls/Presenters/TextPresenter.cs index 1cd7e11564..0841030aaa 100644 --- a/src/Avalonia.Controls/Presenters/TextPresenter.cs +++ b/src/Avalonia.Controls/Presenters/TextPresenter.cs @@ -14,8 +14,8 @@ namespace Avalonia.Controls.Presenters o => o.CaretIndex, (o, v) => o.CaretIndex = v); - public static readonly StyledProperty ShowPasswordTextProperty = - AvaloniaProperty.Register(nameof(ShowPasswordText)); + public static readonly StyledProperty RevealPasswordTextProperty = + AvaloniaProperty.Register(nameof(RevealPasswordText)); public static readonly StyledProperty PasswordCharProperty = AvaloniaProperty.Register(nameof(PasswordChar)); @@ -78,7 +78,7 @@ namespace Avalonia.Controls.Presenters static TextPresenter() { AffectsRender(SelectionBrushProperty); - AffectsMeasure(TextProperty, PasswordCharProperty, ShowPasswordTextProperty, + AffectsMeasure(TextProperty, PasswordCharProperty, RevealPasswordTextProperty, TextAlignmentProperty, TextWrappingProperty, TextBlock.FontSizeProperty, TextBlock.FontStyleProperty, TextBlock.FontWeightProperty, TextBlock.FontFamilyProperty); @@ -87,7 +87,7 @@ namespace Avalonia.Controls.Presenters TextBlock.FontSizeProperty.Changed, TextBlock.FontStyleProperty.Changed, TextBlock.FontWeightProperty.Changed, TextBlock.FontFamilyProperty.Changed, SelectionStartProperty.Changed, SelectionEndProperty.Changed, - SelectionForegroundBrushProperty.Changed, PasswordCharProperty.Changed, ShowPasswordTextProperty.Changed + SelectionForegroundBrushProperty.Changed, PasswordCharProperty.Changed, RevealPasswordTextProperty.Changed ).AddClassHandler((x, _) => x.InvalidateFormattedText()); CaretIndexProperty.Changed.AddClassHandler((x, e) => x.CaretIndexChanged((int)e.NewValue)); @@ -213,10 +213,10 @@ namespace Avalonia.Controls.Presenters set => SetValue(PasswordCharProperty, value); } - public bool ShowPasswordText + public bool RevealPasswordText { - get => GetValue(ShowPasswordTextProperty); - set => SetValue(ShowPasswordTextProperty, value); + get => GetValue(RevealPasswordTextProperty); + set => SetValue(RevealPasswordTextProperty, value); } public IBrush SelectionBrush @@ -435,7 +435,7 @@ namespace Avalonia.Controls.Presenters var text = Text; - if (PasswordChar != default(char) && !ShowPasswordText) + if (PasswordChar != default(char) && !RevealPasswordText) { result = CreateFormattedTextInternal(_constraint, new string(PasswordChar, text?.Length ?? 0)); } diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index 489937147f..0e0d053d88 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -101,8 +101,8 @@ namespace Avalonia.Controls public static readonly StyledProperty InnerRightContentProperty = AvaloniaProperty.Register(nameof(InnerRightContent)); - public static readonly StyledProperty ShowPasswordTextProperty = - AvaloniaProperty.Register(nameof(ShowPasswordText)); + public static readonly StyledProperty RevealPasswordTextProperty = + AvaloniaProperty.Register(nameof(RevealPasswordText)); struct UndoRedoState : IEquatable { @@ -347,10 +347,10 @@ namespace Avalonia.Controls set { SetValue(InnerRightContentProperty, value); } } - public bool ShowPasswordText + public bool RevealPasswordText { - get { return GetValue(ShowPasswordTextProperty); } - set { SetValue(ShowPasswordTextProperty, value); } + get { return GetValue(RevealPasswordTextProperty); } + set { SetValue(RevealPasswordTextProperty, value); } } public TextWrapping TextWrapping diff --git a/src/Avalonia.Themes.Fluent/TextBox.xaml b/src/Avalonia.Themes.Fluent/TextBox.xaml index 8bc8d38c01..bd10fbbe51 100644 --- a/src/Avalonia.Themes.Fluent/TextBox.xaml +++ b/src/Avalonia.Themes.Fluent/TextBox.xaml @@ -10,11 +10,11 @@ 0,0,0,4 - + - + @@ -96,7 +96,7 @@ TextAlignment="{TemplateBinding TextAlignment}" TextWrapping="{TemplateBinding TextWrapping}" PasswordChar="{TemplateBinding PasswordChar}" - ShowPasswordText="{TemplateBinding ShowPasswordText}" + RevealPasswordText="{TemplateBinding RevealPasswordText}" SelectionBrush="{TemplateBinding SelectionBrush}" SelectionForegroundBrush="{TemplateBinding SelectionForegroundBrush}" CaretBrush="{TemplateBinding CaretBrush}" @@ -166,28 +166,20 @@ - - - - - + + + + + + + + + + + + + From 913958732ea144e5221e67cbc0e1962a02d565d2 Mon Sep 17 00:00:00 2001 From: Maksym Katsydan Date: Thu, 13 Aug 2020 21:53:15 -0400 Subject: [PATCH 209/344] Fluent TextBox: Add PasswordBoxRevealButton style --- src/Avalonia.Themes.Fluent/TextBox.xaml | 85 ++++++++++++++++--------- 1 file changed, 56 insertions(+), 29 deletions(-) diff --git a/src/Avalonia.Themes.Fluent/TextBox.xaml b/src/Avalonia.Themes.Fluent/TextBox.xaml index 0fe5f9061f..d73704f64c 100644 --- a/src/Avalonia.Themes.Fluent/TextBox.xaml +++ b/src/Avalonia.Themes.Fluent/TextBox.xaml @@ -11,16 +11,10 @@ 0,0,0,4 - M1169 1024l879 -879l-145 -145l-879 879l-879 -879l-145 145l879 879l-879 879l145 145l879 -879l879 879l145 -145z - - - - - - - - + M 11.416016,10 20,1.4160156 18.583984,0 10,8.5839846 1.4160156,0 0,1.4160156 8.5839844,10 0,18.583985 1.4160156,20 10,11.416015 18.583984,20 20,18.583985 Z + m10.051 7.0032c2.215 0 4.0105 1.7901 4.0105 3.9984s-1.7956 3.9984-4.0105 3.9984c-2.215 0-4.0105-1.7901-4.0105-3.9984s1.7956-3.9984 4.0105-3.9984zm0 1.4994c-1.3844 0-2.5066 1.1188-2.5066 2.499s1.1222 2.499 2.5066 2.499 2.5066-1.1188 2.5066-2.499-1.1222-2.499-2.5066-2.499zm0-5.0026c4.6257 0 8.6188 3.1487 9.7267 7.5613 0.10085 0.40165-0.14399 0.80877-0.54686 0.90931-0.40288 0.10054-0.81122-0.14355-0.91208-0.54521-0.94136-3.7492-4.3361-6.4261-8.2678-6.4261-3.9334 0-7.3292 2.6792-8.2689 6.4306-0.10063 0.40171-0.50884 0.64603-0.91177 0.54571s-0.648-0.5073-0.54737-0.90901c1.106-4.4152 5.1003-7.5667 9.728-7.5667z + - @@ -190,20 +180,36 @@ + + - + - - - - - - From e5644c0b72303aefe6acd06b77a8b41f69b28bbc Mon Sep 17 00:00:00 2001 From: Maksym Katsydan Date: Thu, 13 Aug 2020 22:02:52 -0400 Subject: [PATCH 210/344] Fluent TextBox: Remove multibinding from floatingWatermark Also rename floatingWatermark and watermark --- src/Avalonia.Themes.Fluent/TextBox.xaml | 35 +++++++++++-------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/src/Avalonia.Themes.Fluent/TextBox.xaml b/src/Avalonia.Themes.Fluent/TextBox.xaml index d73704f64c..c661162e5c 100644 --- a/src/Avalonia.Themes.Fluent/TextBox.xaml +++ b/src/Avalonia.Themes.Fluent/TextBox.xaml @@ -54,27 +54,17 @@ - - - - - - - - + - - @@ -135,7 +125,7 @@ - @@ -144,7 +134,7 @@ - @@ -161,6 +151,13 @@ + + + - @@ -120,7 +121,7 @@ - @@ -138,17 +139,17 @@ - - - From a887e3e50e0b9b9d020db50e32f8ecf9042893ec Mon Sep 17 00:00:00 2001 From: Maksym Katsydan Date: Thu, 13 Aug 2020 22:41:45 -0400 Subject: [PATCH 212/344] Fluent TextBox: Return "Hide" password button icon --- src/Avalonia.Themes.Fluent/TextBox.xaml | 45 ++++++++++++++++++------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/src/Avalonia.Themes.Fluent/TextBox.xaml b/src/Avalonia.Themes.Fluent/TextBox.xaml index 515cdccd2c..5eddd54226 100644 --- a/src/Avalonia.Themes.Fluent/TextBox.xaml +++ b/src/Avalonia.Themes.Fluent/TextBox.xaml @@ -13,6 +13,7 @@ 0,0,0,4 M 11.416016,10 20,1.4160156 18.583984,0 10,8.5839846 1.4160156,0 0,1.4160156 8.5839844,10 0,18.583985 1.4160156,20 10,11.416015 18.583984,20 20,18.583985 Z m10.051 7.0032c2.215 0 4.0105 1.7901 4.0105 3.9984s-1.7956 3.9984-4.0105 3.9984c-2.215 0-4.0105-1.7901-4.0105-3.9984s1.7956-3.9984 4.0105-3.9984zm0 1.4994c-1.3844 0-2.5066 1.1188-2.5066 2.499s1.1222 2.499 2.5066 2.499 2.5066-1.1188 2.5066-2.499-1.1222-2.499-2.5066-2.499zm0-5.0026c4.6257 0 8.6188 3.1487 9.7267 7.5613 0.10085 0.40165-0.14399 0.80877-0.54686 0.90931-0.40288 0.10054-0.81122-0.14355-0.91208-0.54521-0.94136-3.7492-4.3361-6.4261-8.2678-6.4261-3.9334 0-7.3292 2.6792-8.2689 6.4306-0.10063 0.40171-0.50884 0.64603-0.91177 0.54571s-0.648-0.5073-0.54737-0.90901c1.106-4.4152 5.1003-7.5667 9.728-7.5667z + m0.21967 0.21965c-0.26627 0.26627-0.29047 0.68293-0.07262 0.97654l0.07262 0.08412 4.0346 4.0346c-1.922 1.3495-3.3585 3.365-3.9554 5.7495-0.10058 0.4018 0.14362 0.8091 0.54543 0.9097 0.40182 0.1005 0.80909-0.1436 0.90968-0.5455 0.52947-2.1151 1.8371-3.8891 3.5802-5.0341l1.8096 1.8098c-0.70751 0.7215-1.1438 1.71-1.1438 2.8003 0 2.2092 1.7909 4 4 4 1.0904 0 2.0788-0.4363 2.8004-1.1438l5.9193 5.9195c0.2929 0.2929 0.7677 0.2929 1.0606 0 0.2663-0.2662 0.2905-0.6829 0.0726-0.9765l-0.0726-0.0841-6.1135-6.1142 0.0012-0.0015-1.2001-1.1979-2.8699-2.8693 2e-3 -8e-4 -2.8812-2.8782 0.0012-0.0018-1.1333-1.1305-4.3064-4.3058c-0.29289-0.29289-0.76777-0.29289-1.0607 0zm7.9844 9.0458 3.5351 3.5351c-0.45 0.4358-1.0633 0.704-1.7392 0.704-1.3807 0-2.5-1.1193-2.5-2.5 0-0.6759 0.26824-1.2892 0.7041-1.7391zm1.7959-5.7655c-1.0003 0-1.9709 0.14807-2.8889 0.425l1.237 1.2362c0.5358-0.10587 1.0883-0.16119 1.6519-0.16119 3.9231 0 7.3099 2.6803 8.2471 6.4332 0.1004 0.4018 0.5075 0.6462 0.9094 0.5459 0.4019-0.1004 0.6463-0.5075 0.5459-0.9094-1.103-4.417-5.0869-7.5697-9.7024-7.5697zm0.1947 3.5093 3.8013 3.8007c-0.1018-2.0569-1.7488-3.7024-3.8013-3.8007z - @@ -240,7 +251,8 @@ @@ -253,9 +265,9 @@ @@ -265,4 +277,11 @@ + + + From 23713366fa02544ee7a994adec943a1525fc7c60 Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Fri, 14 Aug 2020 11:54:09 +0800 Subject: [PATCH 213/344] add support for default theme --- src/Avalonia.Themes.Default/TextBox.xaml | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/Avalonia.Themes.Default/TextBox.xaml b/src/Avalonia.Themes.Default/TextBox.xaml index 6a746dda30..8384cccada 100644 --- a/src/Avalonia.Themes.Default/TextBox.xaml +++ b/src/Avalonia.Themes.Default/TextBox.xaml @@ -35,14 +35,16 @@ - - + + + + IsVisible="{TemplateBinding Text, Converter={x:Static StringConverters.IsNullOrEmpty}}" + Grid.Column="1" Grid.ColumnSpan="1"/> - + CaretBrush="{TemplateBinding CaretBrush}" + Grid.Column="1" Grid.ColumnSpan="1"/> + + From ba11b5d8d0f26267a2a7d7a0eb2cae576c832739 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 14 Aug 2020 10:15:53 +0100 Subject: [PATCH 214/344] add failing unit test, for pw reveal getting reset on focus lost. --- .../TextBoxTests.cs | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs index 217dec2d6d..af3b68f4a0 100644 --- a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs @@ -521,6 +521,40 @@ namespace Avalonia.Controls.UnitTests Assert.Equal(1, lfcount); } } + + [Fact] + public void TextBox_Reveal_Password_Reset_When_Lost_Focus() + { + using (UnitTestApplication.Start(FocusServices)) + { + var target1 = new TextBox + { + Template = CreateTemplate(), + Text = "1234", + PasswordChar = '*' + }; + 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 }; + + target1.Focus(); + target1.RevealPassword = true; + + target2.Focus(); + + Assert.False(target1.RevealPassword); + } + } [Fact] public void Setting_Bound_Text_To_Null_Works() From 03cc2dfff7d646cbc342764a16ab93502fff447b Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 14 Aug 2020 10:16:11 +0100 Subject: [PATCH 215/344] clear reveal password when lose focus. --- src/Avalonia.Controls/TextBox.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index 0ad2a55f19..7e28d88581 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -413,6 +413,7 @@ namespace Avalonia.Controls SelectionStart = 0; SelectionEnd = 0; _presenter?.HideCaret(); + RevealPassword = false; } protected override void OnTextInput(TextInputEventArgs e) From 0daf5f771e91f14df210b32be140b362cbfc6001 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 16 Aug 2020 21:00:55 +0100 Subject: [PATCH 216/344] dont generate sharpgen sources. --- src/Avalonia.Native/Avalonia.Native.csproj | 2 +- src/Avalonia.Native/Generated/Enumerations.cs | 628 ++++ src/Avalonia.Native/Generated/Functions.cs | 5 + src/Avalonia.Native/Generated/Interfaces.cs | 3092 +++++++++++++++++ src/Avalonia.Native/Generated/LocalInterop.cs | 202 ++ src/Avalonia.Native/Generated/Structures.cs | 246 ++ 6 files changed, 4174 insertions(+), 1 deletion(-) create mode 100644 src/Avalonia.Native/Generated/Enumerations.cs create mode 100644 src/Avalonia.Native/Generated/Functions.cs create mode 100644 src/Avalonia.Native/Generated/Interfaces.cs create mode 100644 src/Avalonia.Native/Generated/LocalInterop.cs create mode 100644 src/Avalonia.Native/Generated/Structures.cs diff --git a/src/Avalonia.Native/Avalonia.Native.csproj b/src/Avalonia.Native/Avalonia.Native.csproj index 1a2bdeef1e..9c3eaed2d8 100644 --- a/src/Avalonia.Native/Avalonia.Native.csproj +++ b/src/Avalonia.Native/Avalonia.Native.csproj @@ -19,7 +19,7 @@ - + diff --git a/src/Avalonia.Native/Generated/Enumerations.cs b/src/Avalonia.Native/Generated/Enumerations.cs new file mode 100644 index 0000000000..0b30ce50c0 --- /dev/null +++ b/src/Avalonia.Native/Generated/Enumerations.cs @@ -0,0 +1,628 @@ +// + +namespace Avalonia.Native.Interop +{ + /// + /// No documentation. + /// + /// AvnDragDropEffects + /// AvnDragDropEffects + public enum AvnDragDropEffects : System.Int32 + { + /// + /// No documentation. + /// + /// None + /// None + None = unchecked ((System.Int32)(0)), + /// + /// No documentation. + /// + /// Copy + /// Copy + Copy = unchecked ((System.Int32)(1)), + /// + /// No documentation. + /// + /// Move + /// Move + Move = unchecked ((System.Int32)(2)), + /// + /// No documentation. + /// + /// Link + /// Link + Link = unchecked ((System.Int32)(4))} + + /// + /// No documentation. + /// + /// AvnDragEventType + /// AvnDragEventType + public enum AvnDragEventType : System.Int32 + { + /// + /// No documentation. + /// + /// Enter + /// Enter + Enter = unchecked ((System.Int32)(0)), + /// + /// No documentation. + /// + /// Over + /// Over + Over = unchecked ((System.Int32)(1)), + /// + /// No documentation. + /// + /// Leave + /// Leave + Leave = unchecked ((System.Int32)(2)), + /// + /// No documentation. + /// + /// Drop + /// Drop + Drop = unchecked ((System.Int32)(3))} + + /// + /// No documentation. + /// + /// AvnExtendClientAreaChromeHints + /// AvnExtendClientAreaChromeHints + public enum AvnExtendClientAreaChromeHints : System.Int32 + { + /// + /// No documentation. + /// + /// AvnNoChrome + /// AvnNoChrome + AvnNoChrome = unchecked ((System.Int32)(0)), + /// + /// No documentation. + /// + /// AvnSystemChrome + /// AvnSystemChrome + AvnSystemChrome = unchecked ((System.Int32)(1)), + /// + /// No documentation. + /// + /// AvnPreferSystemChrome + /// AvnPreferSystemChrome + AvnPreferSystemChrome = unchecked ((System.Int32)(2)), + /// + /// No documentation. + /// + /// AvnOSXThickTitleBar + /// AvnOSXThickTitleBar + AvnOSXThickTitleBar = unchecked ((System.Int32)(8)), + /// + /// No documentation. + /// + /// AvnDefaultChrome + /// AvnDefaultChrome + AvnDefaultChrome = unchecked ((System.Int32)(1))} + + /// + /// No documentation. + /// + /// AvnInputModifiers + /// AvnInputModifiers + public enum AvnInputModifiers : System.Int32 + { + /// + /// No documentation. + /// + /// AvnInputModifiersNone + /// AvnInputModifiersNone + AvnInputModifiersNone = unchecked ((System.Int32)(0)), + /// + /// No documentation. + /// + /// Alt + /// Alt + Alt = unchecked ((System.Int32)(1)), + /// + /// No documentation. + /// + /// Control + /// Control + Control = unchecked ((System.Int32)(2)), + /// + /// No documentation. + /// + /// Shift + /// Shift + Shift = unchecked ((System.Int32)(4)), + /// + /// No documentation. + /// + /// Windows + /// Windows + Windows = unchecked ((System.Int32)(8)), + /// + /// No documentation. + /// + /// LeftMouseButton + /// LeftMouseButton + LeftMouseButton = unchecked ((System.Int32)(16)), + /// + /// No documentation. + /// + /// RightMouseButton + /// RightMouseButton + RightMouseButton = unchecked ((System.Int32)(32)), + /// + /// No documentation. + /// + /// MiddleMouseButton + /// MiddleMouseButton + MiddleMouseButton = unchecked ((System.Int32)(64)), + /// + /// No documentation. + /// + /// XButton1MouseButton + /// XButton1MouseButton + XButton1MouseButton = unchecked ((System.Int32)(128)), + /// + /// No documentation. + /// + /// XButton2MouseButton + /// XButton2MouseButton + XButton2MouseButton = unchecked ((System.Int32)(256))} + + /// + /// No documentation. + /// + /// AvnMenuItemToggleType + /// AvnMenuItemToggleType + public enum AvnMenuItemToggleType : System.Int32 + { + /// + /// No documentation. + /// + /// None + /// None + None = unchecked ((System.Int32)(0)), + /// + /// No documentation. + /// + /// CheckMark + /// CheckMark + CheckMark = unchecked ((System.Int32)(1)), + /// + /// No documentation. + /// + /// Radio + /// Radio + Radio = unchecked ((System.Int32)(2))} + + /// + /// No documentation. + /// + /// AvnPixelFormat + /// AvnPixelFormat + public enum AvnPixelFormat : System.Int32 + { + /// + /// No documentation. + /// + /// kAvnRgb565 + /// kAvnRgb565 + KAvnRgb565 = unchecked ((System.Int32)(0)), + /// + /// No documentation. + /// + /// kAvnRgba8888 + /// kAvnRgba8888 + KAvnRgba8888 = unchecked ((System.Int32)(1)), + /// + /// No documentation. + /// + /// kAvnBgra8888 + /// kAvnBgra8888 + KAvnBgra8888 = unchecked ((System.Int32)(2))} + + /// + /// No documentation. + /// + /// AvnRawKeyEventType + /// AvnRawKeyEventType + public enum AvnRawKeyEventType : System.Int32 + { + /// + /// No documentation. + /// + /// KeyDown + /// KeyDown + KeyDown = unchecked ((System.Int32)(0)), + /// + /// No documentation. + /// + /// KeyUp + /// KeyUp + KeyUp = unchecked ((System.Int32)(1))} + + /// + /// No documentation. + /// + /// AvnRawMouseEventType + /// AvnRawMouseEventType + public enum AvnRawMouseEventType : System.Int32 + { + /// + /// No documentation. + /// + /// LeaveWindow + /// LeaveWindow + LeaveWindow = unchecked ((System.Int32)(0)), + /// + /// No documentation. + /// + /// LeftButtonDown + /// LeftButtonDown + LeftButtonDown = unchecked ((System.Int32)(1)), + /// + /// No documentation. + /// + /// LeftButtonUp + /// LeftButtonUp + LeftButtonUp = unchecked ((System.Int32)(2)), + /// + /// No documentation. + /// + /// RightButtonDown + /// RightButtonDown + RightButtonDown = unchecked ((System.Int32)(3)), + /// + /// No documentation. + /// + /// RightButtonUp + /// RightButtonUp + RightButtonUp = unchecked ((System.Int32)(4)), + /// + /// No documentation. + /// + /// MiddleButtonDown + /// MiddleButtonDown + MiddleButtonDown = unchecked ((System.Int32)(5)), + /// + /// No documentation. + /// + /// MiddleButtonUp + /// MiddleButtonUp + MiddleButtonUp = unchecked ((System.Int32)(6)), + /// + /// No documentation. + /// + /// XButton1Down + /// XButton1Down + XButton1Down = unchecked ((System.Int32)(7)), + /// + /// No documentation. + /// + /// XButton1Up + /// XButton1Up + XButton1Up = unchecked ((System.Int32)(8)), + /// + /// No documentation. + /// + /// XButton2Down + /// XButton2Down + XButton2Down = unchecked ((System.Int32)(9)), + /// + /// No documentation. + /// + /// XButton2Up + /// XButton2Up + XButton2Up = unchecked ((System.Int32)(10)), + /// + /// No documentation. + /// + /// Move + /// Move + Move = unchecked ((System.Int32)(11)), + /// + /// No documentation. + /// + /// Wheel + /// Wheel + Wheel = unchecked ((System.Int32)(12)), + /// + /// No documentation. + /// + /// NonClientLeftButtonDown + /// NonClientLeftButtonDown + NonClientLeftButtonDown = unchecked ((System.Int32)(13)), + /// + /// No documentation. + /// + /// TouchBegin + /// TouchBegin + TouchBegin = unchecked ((System.Int32)(14)), + /// + /// No documentation. + /// + /// TouchUpdate + /// TouchUpdate + TouchUpdate = unchecked ((System.Int32)(15)), + /// + /// No documentation. + /// + /// TouchEnd + /// TouchEnd + TouchEnd = unchecked ((System.Int32)(16)), + /// + /// No documentation. + /// + /// TouchCancel + /// TouchCancel + TouchCancel = unchecked ((System.Int32)(17))} + + /// + /// No documentation. + /// + /// AvnStandardCursorType + /// AvnStandardCursorType + public enum AvnStandardCursorType : System.Int32 + { + /// + /// No documentation. + /// + /// CursorArrow + /// CursorArrow + CursorArrow = unchecked ((System.Int32)(0)), + /// + /// No documentation. + /// + /// CursorIbeam + /// CursorIbeam + CursorIbeam = unchecked ((System.Int32)(1)), + /// + /// No documentation. + /// + /// CursorWait + /// CursorWait + CursorWait = unchecked ((System.Int32)(2)), + /// + /// No documentation. + /// + /// CursorCross + /// CursorCross + CursorCross = unchecked ((System.Int32)(3)), + /// + /// No documentation. + /// + /// CursorUpArrow + /// CursorUpArrow + CursorUpArrow = unchecked ((System.Int32)(4)), + /// + /// No documentation. + /// + /// CursorSizeWestEast + /// CursorSizeWestEast + CursorSizeWestEast = unchecked ((System.Int32)(5)), + /// + /// No documentation. + /// + /// CursorSizeNorthSouth + /// CursorSizeNorthSouth + CursorSizeNorthSouth = unchecked ((System.Int32)(6)), + /// + /// No documentation. + /// + /// CursorSizeAll + /// CursorSizeAll + CursorSizeAll = unchecked ((System.Int32)(7)), + /// + /// No documentation. + /// + /// CursorNo + /// CursorNo + CursorNo = unchecked ((System.Int32)(8)), + /// + /// No documentation. + /// + /// CursorHand + /// CursorHand + CursorHand = unchecked ((System.Int32)(9)), + /// + /// No documentation. + /// + /// CursorAppStarting + /// CursorAppStarting + CursorAppStarting = unchecked ((System.Int32)(10)), + /// + /// No documentation. + /// + /// CursorHelp + /// CursorHelp + CursorHelp = unchecked ((System.Int32)(11)), + /// + /// No documentation. + /// + /// CursorTopSide + /// CursorTopSide + CursorTopSide = unchecked ((System.Int32)(12)), + /// + /// No documentation. + /// + /// CursorBottomSize + /// CursorBottomSize + CursorBottomSize = unchecked ((System.Int32)(13)), + /// + /// No documentation. + /// + /// CursorLeftSide + /// CursorLeftSide + CursorLeftSide = unchecked ((System.Int32)(14)), + /// + /// No documentation. + /// + /// CursorRightSide + /// CursorRightSide + CursorRightSide = unchecked ((System.Int32)(15)), + /// + /// No documentation. + /// + /// CursorTopLeftCorner + /// CursorTopLeftCorner + CursorTopLeftCorner = unchecked ((System.Int32)(16)), + /// + /// No documentation. + /// + /// CursorTopRightCorner + /// CursorTopRightCorner + CursorTopRightCorner = unchecked ((System.Int32)(17)), + /// + /// No documentation. + /// + /// CursorBottomLeftCorner + /// CursorBottomLeftCorner + CursorBottomLeftCorner = unchecked ((System.Int32)(18)), + /// + /// No documentation. + /// + /// CursorBottomRightCorner + /// CursorBottomRightCorner + CursorBottomRightCorner = unchecked ((System.Int32)(19)), + /// + /// No documentation. + /// + /// CursorDragMove + /// CursorDragMove + CursorDragMove = unchecked ((System.Int32)(20)), + /// + /// No documentation. + /// + /// CursorDragCopy + /// CursorDragCopy + CursorDragCopy = unchecked ((System.Int32)(21)), + /// + /// No documentation. + /// + /// CursorDragLink + /// CursorDragLink + CursorDragLink = unchecked ((System.Int32)(22)), + /// + /// No documentation. + /// + /// CursorNone + /// CursorNone + CursorNone = unchecked ((System.Int32)(23))} + + /// + /// No documentation. + /// + /// AvnWindowEdge + /// AvnWindowEdge + public enum AvnWindowEdge : System.Int32 + { + /// + /// No documentation. + /// + /// WindowEdgeNorthWest + /// WindowEdgeNorthWest + WindowEdgeNorthWest = unchecked ((System.Int32)(0)), + /// + /// No documentation. + /// + /// WindowEdgeNorth + /// WindowEdgeNorth + WindowEdgeNorth = unchecked ((System.Int32)(1)), + /// + /// No documentation. + /// + /// WindowEdgeNorthEast + /// WindowEdgeNorthEast + WindowEdgeNorthEast = unchecked ((System.Int32)(2)), + /// + /// No documentation. + /// + /// WindowEdgeWest + /// WindowEdgeWest + WindowEdgeWest = unchecked ((System.Int32)(3)), + /// + /// No documentation. + /// + /// WindowEdgeEast + /// WindowEdgeEast + WindowEdgeEast = unchecked ((System.Int32)(4)), + /// + /// No documentation. + /// + /// WindowEdgeSouthWest + /// WindowEdgeSouthWest + WindowEdgeSouthWest = unchecked ((System.Int32)(5)), + /// + /// No documentation. + /// + /// WindowEdgeSouth + /// WindowEdgeSouth + WindowEdgeSouth = unchecked ((System.Int32)(6)), + /// + /// No documentation. + /// + /// WindowEdgeSouthEast + /// WindowEdgeSouthEast + WindowEdgeSouthEast = unchecked ((System.Int32)(7))} + + /// + /// No documentation. + /// + /// AvnWindowState + /// AvnWindowState + public enum AvnWindowState : System.Int32 + { + /// + /// No documentation. + /// + /// Normal + /// Normal + Normal = unchecked ((System.Int32)(0)), + /// + /// No documentation. + /// + /// Minimized + /// Minimized + Minimized = unchecked ((System.Int32)(1)), + /// + /// No documentation. + /// + /// Maximized + /// Maximized + Maximized = unchecked ((System.Int32)(2)), + /// + /// No documentation. + /// + /// FullScreen + /// FullScreen + FullScreen = unchecked ((System.Int32)(3))} + + /// + /// No documentation. + /// + /// SystemDecorations + /// SystemDecorations + public enum SystemDecorations : System.Int32 + { + /// + /// No documentation. + /// + /// SystemDecorationsNone + /// SystemDecorationsNone + SystemDecorationsNone = unchecked ((System.Int32)(0)), + /// + /// No documentation. + /// + /// SystemDecorationsBorderOnly + /// SystemDecorationsBorderOnly + SystemDecorationsBorderOnly = unchecked ((System.Int32)(1)), + /// + /// No documentation. + /// + /// SystemDecorationsFull + /// SystemDecorationsFull + SystemDecorationsFull = unchecked ((System.Int32)(2))} +} \ No newline at end of file diff --git a/src/Avalonia.Native/Generated/Functions.cs b/src/Avalonia.Native/Generated/Functions.cs new file mode 100644 index 0000000000..6ab648dc50 --- /dev/null +++ b/src/Avalonia.Native/Generated/Functions.cs @@ -0,0 +1,5 @@ +// + +namespace Avalonia.Native.Interop +{ +} \ No newline at end of file diff --git a/src/Avalonia.Native/Generated/Interfaces.cs b/src/Avalonia.Native/Generated/Interfaces.cs new file mode 100644 index 0000000000..161ada1e50 --- /dev/null +++ b/src/Avalonia.Native/Generated/Interfaces.cs @@ -0,0 +1,3092 @@ +// + +namespace Avalonia.Native.Interop +{ + [System.Runtime.InteropServices.GuidAttribute("2e2cda0a-9ae5-4f1b-8e20-081a04279f01")] + public partial class IAvaloniaNativeFactory : SharpGen.Runtime.ComObject + { + public IAvaloniaNativeFactory(System.IntPtr nativePtr): base (nativePtr) + { + } + + public static explicit operator IAvaloniaNativeFactory(System.IntPtr nativePtr) => nativePtr == System.IntPtr.Zero ? null : new IAvaloniaNativeFactory(nativePtr); + /// + /// No documentation. + /// + /// GetMacOptions + /// GetMacOptions + public Avalonia.Native.Interop.IAvnMacOptions MacOptions + { + get => GetMacOptions(); + } + + /// + /// No documentation. + /// + /// SetAppMenu + /// SetAppMenu + public Avalonia.Native.Interop.IAvnMenu AppMenu + { + set => SetAppMenu(value); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvaloniaNativeFactory::Initialize([In] IAvnGCHandleDeallocatorCallback* deallocator) + /// IAvaloniaNativeFactory::Initialize + public unsafe void Initialize(Avalonia.Native.Interop.IAvnGCHandleDeallocatorCallback deallocator) + { + System.IntPtr deallocator_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + deallocator_ = SharpGen.Runtime.CppObject.ToCallbackPtr(deallocator); + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (void *)deallocator_, (*(void ***)this._nativePointer)[3]); + System.GC.KeepAlive(deallocator); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// IAvnMacOptions* IAvaloniaNativeFactory::GetMacOptions() + /// IAvaloniaNativeFactory::GetMacOptions + internal unsafe Avalonia.Native.Interop.IAvnMacOptions GetMacOptions() + { + Avalonia.Native.Interop.IAvnMacOptions __result__; + System.IntPtr __result__native = System.IntPtr.Zero; + __result__native = Avalonia.Native.LocalInterop.CalliThisCallSystemIntPtr(this._nativePointer, (*(void ***)this._nativePointer)[4]); + if (__result__native != System.IntPtr.Zero) + __result__ = new Avalonia.Native.Interop.IAvnMacOptions(__result__native); + else + __result__ = null; + return __result__; + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// No documentation. + /// HRESULT IAvaloniaNativeFactory::CreateWindow([In] IAvnWindowEvents* cb,[In] IAvnGlContext* gl,[In] IAvnWindow** ppv) + /// IAvaloniaNativeFactory::CreateWindow + public unsafe Avalonia.Native.Interop.IAvnWindow CreateWindow(Avalonia.Native.Interop.IAvnWindowEvents cb, Avalonia.Native.Interop.IAvnGlContext gl) + { + System.IntPtr cb_ = System.IntPtr.Zero; + System.IntPtr gl_ = System.IntPtr.Zero; + Avalonia.Native.Interop.IAvnWindow vOut; + System.IntPtr vOut_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + cb_ = SharpGen.Runtime.CppObject.ToCallbackPtr(cb); + gl_ = SharpGen.Runtime.CppObject.ToCallbackPtr(gl); + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (void *)cb_, (void *)gl_, &vOut_, (*(void ***)this._nativePointer)[5]); + if (vOut_ != System.IntPtr.Zero) + vOut = new Avalonia.Native.Interop.IAvnWindow(vOut_); + else + vOut = null; + System.GC.KeepAlive(cb); + System.GC.KeepAlive(gl); + __result__.CheckError(); + return vOut; + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// No documentation. + /// HRESULT IAvaloniaNativeFactory::CreatePopup([In] IAvnWindowEvents* cb,[In] IAvnGlContext* gl,[In] IAvnPopup** ppv) + /// IAvaloniaNativeFactory::CreatePopup + public unsafe Avalonia.Native.Interop.IAvnPopup CreatePopup(Avalonia.Native.Interop.IAvnWindowEvents cb, Avalonia.Native.Interop.IAvnGlContext gl) + { + System.IntPtr cb_ = System.IntPtr.Zero; + System.IntPtr gl_ = System.IntPtr.Zero; + Avalonia.Native.Interop.IAvnPopup vOut; + System.IntPtr vOut_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + cb_ = SharpGen.Runtime.CppObject.ToCallbackPtr(cb); + gl_ = SharpGen.Runtime.CppObject.ToCallbackPtr(gl); + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (void *)cb_, (void *)gl_, &vOut_, (*(void ***)this._nativePointer)[6]); + if (vOut_ != System.IntPtr.Zero) + vOut = new Avalonia.Native.Interop.IAvnPopup(vOut_); + else + vOut = null; + System.GC.KeepAlive(cb); + System.GC.KeepAlive(gl); + __result__.CheckError(); + return vOut; + } + + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvaloniaNativeFactory::CreatePlatformThreadingInterface([In] IAvnPlatformThreadingInterface** ppv) + /// IAvaloniaNativeFactory::CreatePlatformThreadingInterface + public unsafe Avalonia.Native.Interop.IAvnPlatformThreadingInterface CreatePlatformThreadingInterface() + { + Avalonia.Native.Interop.IAvnPlatformThreadingInterface vOut; + System.IntPtr vOut_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, &vOut_, (*(void ***)this._nativePointer)[7]); + if (vOut_ != System.IntPtr.Zero) + vOut = new Avalonia.Native.Interop.IAvnPlatformThreadingInterface(vOut_); + else + vOut = null; + __result__.CheckError(); + return vOut; + } + + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvaloniaNativeFactory::CreateSystemDialogs([In] IAvnSystemDialogs** ppv) + /// IAvaloniaNativeFactory::CreateSystemDialogs + public unsafe Avalonia.Native.Interop.IAvnSystemDialogs CreateSystemDialogs() + { + Avalonia.Native.Interop.IAvnSystemDialogs vOut; + System.IntPtr vOut_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, &vOut_, (*(void ***)this._nativePointer)[8]); + if (vOut_ != System.IntPtr.Zero) + vOut = new Avalonia.Native.Interop.IAvnSystemDialogs(vOut_); + else + vOut = null; + __result__.CheckError(); + return vOut; + } + + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvaloniaNativeFactory::CreateScreens([In] IAvnScreens** ppv) + /// IAvaloniaNativeFactory::CreateScreens + public unsafe Avalonia.Native.Interop.IAvnScreens CreateScreens() + { + Avalonia.Native.Interop.IAvnScreens vOut; + System.IntPtr vOut_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, &vOut_, (*(void ***)this._nativePointer)[9]); + if (vOut_ != System.IntPtr.Zero) + vOut = new Avalonia.Native.Interop.IAvnScreens(vOut_); + else + vOut = null; + __result__.CheckError(); + return vOut; + } + + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvaloniaNativeFactory::CreateClipboard([In] IAvnClipboard** ppv) + /// IAvaloniaNativeFactory::CreateClipboard + public unsafe Avalonia.Native.Interop.IAvnClipboard CreateClipboard() + { + Avalonia.Native.Interop.IAvnClipboard vOut; + System.IntPtr vOut_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, &vOut_, (*(void ***)this._nativePointer)[10]); + if (vOut_ != System.IntPtr.Zero) + vOut = new Avalonia.Native.Interop.IAvnClipboard(vOut_); + else + vOut = null; + __result__.CheckError(); + return vOut; + } + + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvaloniaNativeFactory::CreateDndClipboard([In] IAvnClipboard** ppv) + /// IAvaloniaNativeFactory::CreateDndClipboard + public unsafe Avalonia.Native.Interop.IAvnClipboard CreateDndClipboard() + { + Avalonia.Native.Interop.IAvnClipboard vOut; + System.IntPtr vOut_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, &vOut_, (*(void ***)this._nativePointer)[11]); + if (vOut_ != System.IntPtr.Zero) + vOut = new Avalonia.Native.Interop.IAvnClipboard(vOut_); + else + vOut = null; + __result__.CheckError(); + return vOut; + } + + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvaloniaNativeFactory::CreateCursorFactory([In] IAvnCursorFactory** ppv) + /// IAvaloniaNativeFactory::CreateCursorFactory + public unsafe Avalonia.Native.Interop.IAvnCursorFactory CreateCursorFactory() + { + Avalonia.Native.Interop.IAvnCursorFactory vOut; + System.IntPtr vOut_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, &vOut_, (*(void ***)this._nativePointer)[12]); + if (vOut_ != System.IntPtr.Zero) + vOut = new Avalonia.Native.Interop.IAvnCursorFactory(vOut_); + else + vOut = null; + __result__.CheckError(); + return vOut; + } + + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvaloniaNativeFactory::ObtainGlDisplay([In] IAvnGlDisplay** ppv) + /// IAvaloniaNativeFactory::ObtainGlDisplay + public unsafe Avalonia.Native.Interop.IAvnGlDisplay ObtainGlDisplay() + { + Avalonia.Native.Interop.IAvnGlDisplay vOut; + System.IntPtr vOut_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, &vOut_, (*(void ***)this._nativePointer)[13]); + if (vOut_ != System.IntPtr.Zero) + vOut = new Avalonia.Native.Interop.IAvnGlDisplay(vOut_); + else + vOut = null; + __result__.CheckError(); + return vOut; + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvaloniaNativeFactory::SetAppMenu([In] IAvnMenu* menu) + /// IAvaloniaNativeFactory::SetAppMenu + internal unsafe void SetAppMenu(Avalonia.Native.Interop.IAvnMenu menu) + { + System.IntPtr menu_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + menu_ = SharpGen.Runtime.CppObject.ToCallbackPtr(menu); + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (void *)menu_, (*(void ***)this._nativePointer)[14]); + System.GC.KeepAlive(menu); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvaloniaNativeFactory::CreateMenu([In] IAvnMenuEvents* cb,[In] IAvnMenu** ppv) + /// IAvaloniaNativeFactory::CreateMenu + public unsafe Avalonia.Native.Interop.IAvnMenu CreateMenu(Avalonia.Native.Interop.IAvnMenuEvents cb) + { + System.IntPtr cb_ = System.IntPtr.Zero; + Avalonia.Native.Interop.IAvnMenu vOut; + System.IntPtr vOut_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + cb_ = SharpGen.Runtime.CppObject.ToCallbackPtr(cb); + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (void *)cb_, &vOut_, (*(void ***)this._nativePointer)[15]); + if (vOut_ != System.IntPtr.Zero) + vOut = new Avalonia.Native.Interop.IAvnMenu(vOut_); + else + vOut = null; + System.GC.KeepAlive(cb); + __result__.CheckError(); + return vOut; + } + + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvaloniaNativeFactory::CreateMenuItem([In] IAvnMenuItem** ppv) + /// IAvaloniaNativeFactory::CreateMenuItem + public unsafe Avalonia.Native.Interop.IAvnMenuItem CreateMenuItem() + { + Avalonia.Native.Interop.IAvnMenuItem vOut; + System.IntPtr vOut_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, &vOut_, (*(void ***)this._nativePointer)[16]); + if (vOut_ != System.IntPtr.Zero) + vOut = new Avalonia.Native.Interop.IAvnMenuItem(vOut_); + else + vOut = null; + __result__.CheckError(); + return vOut; + } + + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvaloniaNativeFactory::CreateMenuItemSeperator([In] IAvnMenuItem** ppv) + /// IAvaloniaNativeFactory::CreateMenuItemSeperator + public unsafe Avalonia.Native.Interop.IAvnMenuItem CreateMenuItemSeperator() + { + Avalonia.Native.Interop.IAvnMenuItem vOut; + System.IntPtr vOut_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, &vOut_, (*(void ***)this._nativePointer)[17]); + if (vOut_ != System.IntPtr.Zero) + vOut = new Avalonia.Native.Interop.IAvnMenuItem(vOut_); + else + vOut = null; + __result__.CheckError(); + return vOut; + } + } + + class IAvnActionCallbackShadow : SharpGen.Runtime.ComObjectShadow + { + protected unsafe class IAvnActionCallbackVtbl : SharpGen.Runtime.ComObjectShadow.ComObjectVtbl + { + public IAvnActionCallbackVtbl(int numberOfCallbackMethods): base (numberOfCallbackMethods + 1) + { + AddMethod(new RunDelegate(Run)); + } + + [System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(System.Runtime.InteropServices.CallingConvention.ThisCall)] + private delegate void RunDelegate(System.IntPtr thisObject); + private static unsafe void Run(System.IntPtr thisObject) + { + try + { + IAvnActionCallback @this = (IAvnActionCallback)ToShadow(thisObject).Callback; + @this.Run(); + } + catch (System.Exception __exception__) + { + IAvnActionCallback @this = (IAvnActionCallback)ToShadow(thisObject).Callback; + (@this as SharpGen.Runtime.IExceptionCallback)?.RaiseException(__exception__); + } + } + } + + protected override SharpGen.Runtime.CppObjectVtbl Vtbl + { + get; + } + + = new Avalonia.Native.Interop.IAvnActionCallbackShadow.IAvnActionCallbackVtbl(0); + } + + [System.Runtime.InteropServices.GuidAttribute("2e2cda0a-9ae5-4f1b-8e20-081a04279f08"), SharpGen.Runtime.ShadowAttribute(typeof (Avalonia.Native.Interop.IAvnActionCallbackShadow))] + public partial interface IAvnActionCallback : SharpGen.Runtime.IUnknown + { + void Run(); + } + + [System.Runtime.InteropServices.GuidAttribute("2e2cda0a-9ae5-4f1b-8e20-081a04279f0f")] + public partial class IAvnClipboard : SharpGen.Runtime.ComObject + { + public IAvnClipboard(System.IntPtr nativePtr): base (nativePtr) + { + } + + public static explicit operator IAvnClipboard(System.IntPtr nativePtr) => nativePtr == System.IntPtr.Zero ? null : new IAvnClipboard(nativePtr); + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnClipboard::GetText([In] char* type,[In] IAvnString** ppv) + /// IAvnClipboard::GetText + public unsafe Avalonia.Native.Interop.IAvnString GetText(System.String type) + { + System.IntPtr type_; + Avalonia.Native.Interop.IAvnString vOut; + System.IntPtr vOut_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + type_ = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(type); + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (void *)type_, &vOut_, (*(void ***)this._nativePointer)[3]); + if (vOut_ != System.IntPtr.Zero) + vOut = new Avalonia.Native.Interop.IAvnString(vOut_); + else + vOut = null; + System.Runtime.InteropServices.Marshal.FreeHGlobal(type_); + __result__.CheckError(); + return vOut; + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// No documentation. + /// HRESULT IAvnClipboard::SetText([In] char* type,[In] void* utf8Text) + /// IAvnClipboard::SetText + public unsafe void SetText(System.String type, System.IntPtr utf8Text) + { + System.IntPtr type_; + SharpGen.Runtime.Result __result__; + type_ = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(type); + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (void *)type_, (void *)utf8Text, (*(void ***)this._nativePointer)[4]); + System.Runtime.InteropServices.Marshal.FreeHGlobal(type_); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvnClipboard::ObtainFormats([In] IAvnStringArray** ppv) + /// IAvnClipboard::ObtainFormats + public unsafe Avalonia.Native.Interop.IAvnStringArray ObtainFormats() + { + Avalonia.Native.Interop.IAvnStringArray vOut; + System.IntPtr vOut_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, &vOut_, (*(void ***)this._nativePointer)[5]); + if (vOut_ != System.IntPtr.Zero) + vOut = new Avalonia.Native.Interop.IAvnStringArray(vOut_); + else + vOut = null; + __result__.CheckError(); + return vOut; + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnClipboard::GetStrings([In] char* type,[In] IAvnStringArray** ppv) + /// IAvnClipboard::GetStrings + public unsafe Avalonia.Native.Interop.IAvnStringArray GetStrings(System.String type) + { + System.IntPtr type_; + Avalonia.Native.Interop.IAvnStringArray vOut; + System.IntPtr vOut_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + type_ = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(type); + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (void *)type_, &vOut_, (*(void ***)this._nativePointer)[6]); + if (vOut_ != System.IntPtr.Zero) + vOut = new Avalonia.Native.Interop.IAvnStringArray(vOut_); + else + vOut = null; + System.Runtime.InteropServices.Marshal.FreeHGlobal(type_); + __result__.CheckError(); + return vOut; + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// No documentation. + /// No documentation. + /// HRESULT IAvnClipboard::SetBytes([In] char* type,[In] void* utf8Text,[In] int len) + /// IAvnClipboard::SetBytes + public unsafe void SetBytes(System.String type, System.IntPtr utf8Text, System.Int32 len) + { + System.IntPtr type_; + SharpGen.Runtime.Result __result__; + type_ = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(type); + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (void *)type_, (void *)utf8Text, len, (*(void ***)this._nativePointer)[7]); + System.Runtime.InteropServices.Marshal.FreeHGlobal(type_); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnClipboard::GetBytes([In] char* type,[In] IAvnString** ppv) + /// IAvnClipboard::GetBytes + public unsafe Avalonia.Native.Interop.IAvnString GetBytes(System.String type) + { + System.IntPtr type_; + Avalonia.Native.Interop.IAvnString vOut; + System.IntPtr vOut_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + type_ = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(type); + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (void *)type_, &vOut_, (*(void ***)this._nativePointer)[8]); + if (vOut_ != System.IntPtr.Zero) + vOut = new Avalonia.Native.Interop.IAvnString(vOut_); + else + vOut = null; + System.Runtime.InteropServices.Marshal.FreeHGlobal(type_); + __result__.CheckError(); + return vOut; + } + + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvnClipboard::Clear() + /// IAvnClipboard::Clear + public unsafe void Clear() + { + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (*(void ***)this._nativePointer)[9]); + __result__.CheckError(); + } + } + + [System.Runtime.InteropServices.GuidAttribute("2e2cda0a-9ae5-4f1b-8e20-081a04279f10")] + public partial class IAvnCursor : SharpGen.Runtime.ComObject + { + public IAvnCursor(System.IntPtr nativePtr): base (nativePtr) + { + } + + public static explicit operator IAvnCursor(System.IntPtr nativePtr) => nativePtr == System.IntPtr.Zero ? null : new IAvnCursor(nativePtr); + } + + [System.Runtime.InteropServices.GuidAttribute("2e2cda0a-9ae5-4f1b-8e20-081a04279f11")] + public partial class IAvnCursorFactory : SharpGen.Runtime.ComObject + { + public IAvnCursorFactory(System.IntPtr nativePtr): base (nativePtr) + { + } + + public static explicit operator IAvnCursorFactory(System.IntPtr nativePtr) => nativePtr == System.IntPtr.Zero ? null : new IAvnCursorFactory(nativePtr); + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnCursorFactory::GetCursor([In] AvnStandardCursorType cursorType,[Out] IAvnCursor** retOut) + /// IAvnCursorFactory::GetCursor + public unsafe Avalonia.Native.Interop.IAvnCursor GetCursor(Avalonia.Native.Interop.AvnStandardCursorType cursorType) + { + Avalonia.Native.Interop.IAvnCursor retOut; + System.IntPtr retOut_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, unchecked ((System.Int32)cursorType), &retOut_, (*(void ***)this._nativePointer)[3]); + if (retOut_ != System.IntPtr.Zero) + retOut = new Avalonia.Native.Interop.IAvnCursor(retOut_); + else + retOut = null; + __result__.CheckError(); + return retOut; + } + } + + class IAvnDndResultCallbackShadow : SharpGen.Runtime.ComObjectShadow + { + protected unsafe class IAvnDndResultCallbackVtbl : SharpGen.Runtime.ComObjectShadow.ComObjectVtbl + { + public IAvnDndResultCallbackVtbl(int numberOfCallbackMethods): base (numberOfCallbackMethods + 1) + { + AddMethod(new OnDragAndDropCompleteDelegate(OnDragAndDropComplete)); + } + + [System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(System.Runtime.InteropServices.CallingConvention.ThisCall)] + private delegate void OnDragAndDropCompleteDelegate(System.IntPtr thisObject, int arg0); + private static unsafe void OnDragAndDropComplete(System.IntPtr thisObject, int param0) + { + try + { + Avalonia.Native.Interop.AvnDragDropEffects effecct = default (Avalonia.Native.Interop.AvnDragDropEffects); + effecct = (Avalonia.Native.Interop.AvnDragDropEffects)param0; + IAvnDndResultCallback @this = (IAvnDndResultCallback)ToShadow(thisObject).Callback; + @this.OnDragAndDropComplete(effecct); + } + catch (System.Exception __exception__) + { + IAvnDndResultCallback @this = (IAvnDndResultCallback)ToShadow(thisObject).Callback; + (@this as SharpGen.Runtime.IExceptionCallback)?.RaiseException(__exception__); + } + } + } + + protected override SharpGen.Runtime.CppObjectVtbl Vtbl + { + get; + } + + = new Avalonia.Native.Interop.IAvnDndResultCallbackShadow.IAvnDndResultCallbackVtbl(0); + } + + [System.Runtime.InteropServices.GuidAttribute("2e2cda0a-9ae5-4f1b-8e20-081a04279f21"), SharpGen.Runtime.ShadowAttribute(typeof (Avalonia.Native.Interop.IAvnDndResultCallbackShadow))] + public partial interface IAvnDndResultCallback : SharpGen.Runtime.IUnknown + { + void OnDragAndDropComplete(Avalonia.Native.Interop.AvnDragDropEffects effecct); + } + + class IAvnGCHandleDeallocatorCallbackShadow : SharpGen.Runtime.ComObjectShadow + { + protected unsafe class IAvnGCHandleDeallocatorCallbackVtbl : SharpGen.Runtime.ComObjectShadow.ComObjectVtbl + { + public IAvnGCHandleDeallocatorCallbackVtbl(int numberOfCallbackMethods): base (numberOfCallbackMethods + 1) + { + AddMethod(new FreeGCHandleDelegate(FreeGCHandle)); + } + + [System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(System.Runtime.InteropServices.CallingConvention.ThisCall)] + private delegate void FreeGCHandleDelegate(System.IntPtr thisObject, void *arg0); + private static unsafe void FreeGCHandle(System.IntPtr thisObject, void *param0) + { + try + { + System.IntPtr handle = default (System.IntPtr); + handle = (System.IntPtr)param0; + IAvnGCHandleDeallocatorCallback @this = (IAvnGCHandleDeallocatorCallback)ToShadow(thisObject).Callback; + @this.FreeGCHandle(handle); + } + catch (System.Exception __exception__) + { + IAvnGCHandleDeallocatorCallback @this = (IAvnGCHandleDeallocatorCallback)ToShadow(thisObject).Callback; + (@this as SharpGen.Runtime.IExceptionCallback)?.RaiseException(__exception__); + } + } + } + + protected override SharpGen.Runtime.CppObjectVtbl Vtbl + { + get; + } + + = new Avalonia.Native.Interop.IAvnGCHandleDeallocatorCallbackShadow.IAvnGCHandleDeallocatorCallbackVtbl(0); + } + + [System.Runtime.InteropServices.GuidAttribute("2e2cda0a-9ae5-4f1b-8e20-081a04279f22"), SharpGen.Runtime.ShadowAttribute(typeof (Avalonia.Native.Interop.IAvnGCHandleDeallocatorCallbackShadow))] + public partial interface IAvnGCHandleDeallocatorCallback : SharpGen.Runtime.IUnknown + { + void FreeGCHandle(System.IntPtr handle); + } + + [System.Runtime.InteropServices.GuidAttribute("2e2cda0a-9ae5-4f1b-8e20-081a04279f14")] + public partial class IAvnGlContext : SharpGen.Runtime.ComObject + { + public IAvnGlContext(System.IntPtr nativePtr): base (nativePtr) + { + } + + public static explicit operator IAvnGlContext(System.IntPtr nativePtr) => nativePtr == System.IntPtr.Zero ? null : new IAvnGlContext(nativePtr); + /// + /// No documentation. + /// + /// GetSampleCount + /// GetSampleCount + public System.Int32 SampleCount + { + get => GetSampleCount(); + } + + /// + /// No documentation. + /// + /// GetStencilSize + /// GetStencilSize + public System.Int32 StencilSize + { + get => GetStencilSize(); + } + + /// + /// No documentation. + /// + /// GetNativeHandle + /// GetNativeHandle + public System.IntPtr NativeHandle + { + get => GetNativeHandle(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvnGlContext::MakeCurrent([In] IUnknown** ppv) + /// IAvnGlContext::MakeCurrent + public unsafe SharpGen.Runtime.IUnknown MakeCurrent() + { + SharpGen.Runtime.IUnknown vOut; + System.IntPtr vOut_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, &vOut_, (*(void ***)this._nativePointer)[3]); + if (vOut_ != System.IntPtr.Zero) + vOut = new SharpGen.Runtime.ComObject(vOut_); + else + vOut = null; + __result__.CheckError(); + return vOut; + } + + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvnGlContext::LegacyMakeCurrent() + /// IAvnGlContext::LegacyMakeCurrent + public unsafe void LegacyMakeCurrent() + { + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (*(void ***)this._nativePointer)[4]); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// int IAvnGlContext::GetSampleCount() + /// IAvnGlContext::GetSampleCount + internal unsafe System.Int32 GetSampleCount() + { + System.Int32 __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (*(void ***)this._nativePointer)[5]); + return __result__; + } + + /// + /// No documentation. + /// + /// No documentation. + /// int IAvnGlContext::GetStencilSize() + /// IAvnGlContext::GetStencilSize + internal unsafe System.Int32 GetStencilSize() + { + System.Int32 __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (*(void ***)this._nativePointer)[6]); + return __result__; + } + + /// + /// No documentation. + /// + /// No documentation. + /// void* IAvnGlContext::GetNativeHandle() + /// IAvnGlContext::GetNativeHandle + internal unsafe System.IntPtr GetNativeHandle() + { + System.IntPtr __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallSystemIntPtr(this._nativePointer, (*(void ***)this._nativePointer)[7]); + return __result__; + } + } + + [System.Runtime.InteropServices.GuidAttribute("2e2cda0a-9ae5-4f1b-8e20-081a04279f13")] + public partial class IAvnGlDisplay : SharpGen.Runtime.ComObject + { + public IAvnGlDisplay(System.IntPtr nativePtr): base (nativePtr) + { + } + + public static explicit operator IAvnGlDisplay(System.IntPtr nativePtr) => nativePtr == System.IntPtr.Zero ? null : new IAvnGlDisplay(nativePtr); + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnGlDisplay::CreateContext([In] IAvnGlContext* share,[In] IAvnGlContext** ppv) + /// IAvnGlDisplay::CreateContext + public unsafe Avalonia.Native.Interop.IAvnGlContext CreateContext(Avalonia.Native.Interop.IAvnGlContext share) + { + System.IntPtr share_ = System.IntPtr.Zero; + Avalonia.Native.Interop.IAvnGlContext vOut; + System.IntPtr vOut_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + share_ = SharpGen.Runtime.CppObject.ToCallbackPtr(share); + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (void *)share_, &vOut_, (*(void ***)this._nativePointer)[3]); + if (vOut_ != System.IntPtr.Zero) + vOut = new Avalonia.Native.Interop.IAvnGlContext(vOut_); + else + vOut = null; + System.GC.KeepAlive(share); + __result__.CheckError(); + return vOut; + } + + /// + /// No documentation. + /// + /// void IAvnGlDisplay::LegacyClearCurrentContext() + /// IAvnGlDisplay::LegacyClearCurrentContext + public unsafe void LegacyClearCurrentContext() + { + Avalonia.Native.LocalInterop.CalliThisCallvoid(this._nativePointer, (*(void ***)this._nativePointer)[4]); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnGlDisplay::WrapContext([In] void* native,[In] IAvnGlContext** ppv) + /// IAvnGlDisplay::WrapContext + public unsafe Avalonia.Native.Interop.IAvnGlContext WrapContext(System.IntPtr native) + { + Avalonia.Native.Interop.IAvnGlContext vOut; + System.IntPtr vOut_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (void *)native, &vOut_, (*(void ***)this._nativePointer)[5]); + if (vOut_ != System.IntPtr.Zero) + vOut = new Avalonia.Native.Interop.IAvnGlContext(vOut_); + else + vOut = null; + __result__.CheckError(); + return vOut; + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// void* IAvnGlDisplay::GetProcAddress([In] char* proc) + /// IAvnGlDisplay::GetProcAddress + public unsafe System.IntPtr GetProcAddress(System.String rocRef) + { + System.IntPtr rocRef_; + System.IntPtr __result__; + rocRef_ = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(rocRef); + __result__ = Avalonia.Native.LocalInterop.CalliThisCallSystemIntPtr(this._nativePointer, (void *)rocRef_, (*(void ***)this._nativePointer)[6]); + System.Runtime.InteropServices.Marshal.FreeHGlobal(rocRef_); + return __result__; + } + } + + [System.Runtime.InteropServices.GuidAttribute("2e2cda0a-9ae5-4f1b-8e20-081a04279f16")] + public partial class IAvnGlSurfaceRenderingSession : SharpGen.Runtime.ComObject + { + public IAvnGlSurfaceRenderingSession(System.IntPtr nativePtr): base (nativePtr) + { + } + + public static explicit operator IAvnGlSurfaceRenderingSession(System.IntPtr nativePtr) => nativePtr == System.IntPtr.Zero ? null : new IAvnGlSurfaceRenderingSession(nativePtr); + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvnGlSurfaceRenderingSession::GetPixelSize([In] AvnPixelSize* ret) + /// IAvnGlSurfaceRenderingSession::GetPixelSize + public unsafe Avalonia.Native.Interop.AvnPixelSize GetPixelSize() + { + Avalonia.Native.Interop.AvnPixelSize ret; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, &ret, (*(void ***)this._nativePointer)[3]); + __result__.CheckError(); + return ret; + } + + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvnGlSurfaceRenderingSession::GetScaling([In] double* ret) + /// IAvnGlSurfaceRenderingSession::GetScaling + public unsafe System.Double GetScaling() + { + System.Double ret; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, &ret, (*(void ***)this._nativePointer)[4]); + __result__.CheckError(); + return ret; + } + } + + [System.Runtime.InteropServices.GuidAttribute("2e2cda0a-9ae5-4f1b-8e20-081a04279f15")] + public partial class IAvnGlSurfaceRenderTarget : SharpGen.Runtime.ComObject + { + public IAvnGlSurfaceRenderTarget(System.IntPtr nativePtr): base (nativePtr) + { + } + + public static explicit operator IAvnGlSurfaceRenderTarget(System.IntPtr nativePtr) => nativePtr == System.IntPtr.Zero ? null : new IAvnGlSurfaceRenderTarget(nativePtr); + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvnGlSurfaceRenderTarget::BeginDrawing([In] IAvnGlSurfaceRenderingSession** ret) + /// IAvnGlSurfaceRenderTarget::BeginDrawing + public unsafe Avalonia.Native.Interop.IAvnGlSurfaceRenderingSession BeginDrawing() + { + Avalonia.Native.Interop.IAvnGlSurfaceRenderingSession ret; + System.IntPtr ret_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, &ret_, (*(void ***)this._nativePointer)[3]); + if (ret_ != System.IntPtr.Zero) + ret = new Avalonia.Native.Interop.IAvnGlSurfaceRenderingSession(ret_); + else + ret = null; + __result__.CheckError(); + return ret; + } + } + + [System.Runtime.InteropServices.GuidAttribute("2e2cda0a-9ae5-4f1b-8e20-081a04279f0a")] + public partial class IAvnLoopCancellation : SharpGen.Runtime.ComObject + { + public IAvnLoopCancellation(System.IntPtr nativePtr): base (nativePtr) + { + } + + public static explicit operator IAvnLoopCancellation(System.IntPtr nativePtr) => nativePtr == System.IntPtr.Zero ? null : new IAvnLoopCancellation(nativePtr); + /// + /// No documentation. + /// + /// void IAvnLoopCancellation::Cancel() + /// IAvnLoopCancellation::Cancel + public unsafe void Cancel() + { + Avalonia.Native.LocalInterop.CalliThisCallvoid(this._nativePointer, (*(void ***)this._nativePointer)[3]); + } + } + + [System.Runtime.InteropServices.GuidAttribute("2e2cda0a-9ae5-4f1b-8e20-081a04279f07")] + public partial class IAvnMacOptions : SharpGen.Runtime.ComObject + { + public IAvnMacOptions(System.IntPtr nativePtr): base (nativePtr) + { + } + + public static explicit operator IAvnMacOptions(System.IntPtr nativePtr) => nativePtr == System.IntPtr.Zero ? null : new IAvnMacOptions(nativePtr); + /// + /// No documentation. + /// + /// SetShowInDock + /// SetShowInDock + public System.Int32 ShowInDock + { + set => SetShowInDock(value); + } + + /// + /// No documentation. + /// + /// SetApplicationTitle + /// SetApplicationTitle + public System.IntPtr ApplicationTitle + { + set => SetApplicationTitle(value); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnMacOptions::SetShowInDock([In] int show) + /// IAvnMacOptions::SetShowInDock + internal unsafe void SetShowInDock(System.Int32 show) + { + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, show, (*(void ***)this._nativePointer)[3]); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnMacOptions::SetApplicationTitle([In] void* utf8string) + /// IAvnMacOptions::SetApplicationTitle + internal unsafe void SetApplicationTitle(System.IntPtr utf8string) + { + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (void *)utf8string, (*(void ***)this._nativePointer)[4]); + __result__.CheckError(); + } + } + + [System.Runtime.InteropServices.GuidAttribute("2e2cda0a-9ae5-4f1b-8e20-081a04279f17")] + public partial class IAvnMenu : SharpGen.Runtime.ComObject + { + public IAvnMenu(System.IntPtr nativePtr): base (nativePtr) + { + } + + public static explicit operator IAvnMenu(System.IntPtr nativePtr) => nativePtr == System.IntPtr.Zero ? null : new IAvnMenu(nativePtr); + /// + /// No documentation. + /// + /// SetTitle + /// SetTitle + public System.IntPtr Title + { + set => SetTitle(value); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// No documentation. + /// HRESULT IAvnMenu::InsertItem([In] int index,[In] IAvnMenuItem* item) + /// IAvnMenu::InsertItem + public unsafe void InsertItem(System.Int32 index, Avalonia.Native.Interop.IAvnMenuItem item) + { + System.IntPtr item_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + item_ = SharpGen.Runtime.CppObject.ToCallbackPtr(item); + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, index, (void *)item_, (*(void ***)this._nativePointer)[3]); + System.GC.KeepAlive(item); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnMenu::RemoveItem([In] IAvnMenuItem* item) + /// IAvnMenu::RemoveItem + public unsafe void RemoveItem(Avalonia.Native.Interop.IAvnMenuItem item) + { + System.IntPtr item_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + item_ = SharpGen.Runtime.CppObject.ToCallbackPtr(item); + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (void *)item_, (*(void ***)this._nativePointer)[4]); + System.GC.KeepAlive(item); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnMenu::SetTitle([In] void* utf8String) + /// IAvnMenu::SetTitle + internal unsafe void SetTitle(System.IntPtr utf8String) + { + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (void *)utf8String, (*(void ***)this._nativePointer)[5]); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvnMenu::Clear() + /// IAvnMenu::Clear + public unsafe void Clear() + { + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (*(void ***)this._nativePointer)[6]); + __result__.CheckError(); + } + } + + class IAvnMenuEventsShadow : SharpGen.Runtime.ComObjectShadow + { + protected unsafe class IAvnMenuEventsVtbl : SharpGen.Runtime.ComObjectShadow.ComObjectVtbl + { + public IAvnMenuEventsVtbl(int numberOfCallbackMethods): base (numberOfCallbackMethods + 1) + { + AddMethod(new NeedsUpdateDelegate(NeedsUpdate)); + } + + [System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(System.Runtime.InteropServices.CallingConvention.ThisCall)] + private delegate void NeedsUpdateDelegate(System.IntPtr thisObject); + private static unsafe void NeedsUpdate(System.IntPtr thisObject) + { + try + { + IAvnMenuEvents @this = (IAvnMenuEvents)ToShadow(thisObject).Callback; + @this.NeedsUpdate(); + } + catch (System.Exception __exception__) + { + IAvnMenuEvents @this = (IAvnMenuEvents)ToShadow(thisObject).Callback; + (@this as SharpGen.Runtime.IExceptionCallback)?.RaiseException(__exception__); + } + } + } + + protected override SharpGen.Runtime.CppObjectVtbl Vtbl + { + get; + } + + = new Avalonia.Native.Interop.IAvnMenuEventsShadow.IAvnMenuEventsVtbl(0); + } + + [System.Runtime.InteropServices.GuidAttribute("2e2cda0a-9ae5-4f1b-8e20-081a04279f1A"), SharpGen.Runtime.ShadowAttribute(typeof (Avalonia.Native.Interop.IAvnMenuEventsShadow))] + public partial interface IAvnMenuEvents : SharpGen.Runtime.IUnknown + { + void NeedsUpdate(); + } + + [System.Runtime.InteropServices.GuidAttribute("2e2cda0a-9ae5-4f1b-8e20-081a04279f19")] + public partial class IAvnMenuItem : SharpGen.Runtime.ComObject + { + public IAvnMenuItem(System.IntPtr nativePtr): base (nativePtr) + { + } + + public static explicit operator IAvnMenuItem(System.IntPtr nativePtr) => nativePtr == System.IntPtr.Zero ? null : new IAvnMenuItem(nativePtr); + /// + /// No documentation. + /// + /// SetSubMenu + /// SetSubMenu + public Avalonia.Native.Interop.IAvnMenu SubMenu + { + set => SetSubMenu(value); + } + + /// + /// No documentation. + /// + /// SetTitle + /// SetTitle + public System.IntPtr Title + { + set => SetTitle(value); + } + + /// + /// No documentation. + /// + /// SetIsChecked + /// SetIsChecked + public System.Boolean IsChecked + { + set => SetIsChecked(value); + } + + /// + /// No documentation. + /// + /// SetToggleType + /// SetToggleType + public Avalonia.Native.Interop.AvnMenuItemToggleType ToggleType + { + set => SetToggleType(value); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnMenuItem::SetSubMenu([In] IAvnMenu* menu) + /// IAvnMenuItem::SetSubMenu + internal unsafe void SetSubMenu(Avalonia.Native.Interop.IAvnMenu menu) + { + System.IntPtr menu_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + menu_ = SharpGen.Runtime.CppObject.ToCallbackPtr(menu); + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (void *)menu_, (*(void ***)this._nativePointer)[3]); + System.GC.KeepAlive(menu); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnMenuItem::SetTitle([In] void* utf8String) + /// IAvnMenuItem::SetTitle + internal unsafe void SetTitle(System.IntPtr utf8String) + { + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (void *)utf8String, (*(void ***)this._nativePointer)[4]); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// No documentation. + /// HRESULT IAvnMenuItem::SetGesture([In] void* utf8String,[In] AvnInputModifiers modifiers) + /// IAvnMenuItem::SetGesture + public unsafe void SetGesture(System.IntPtr utf8String, Avalonia.Native.Interop.AvnInputModifiers modifiers) + { + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (void *)utf8String, unchecked ((System.Int32)modifiers), (*(void ***)this._nativePointer)[5]); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// No documentation. + /// HRESULT IAvnMenuItem::SetAction([In] IAvnPredicateCallback* predicate,[In] IAvnActionCallback* callback) + /// IAvnMenuItem::SetAction + public unsafe void SetAction(Avalonia.Native.Interop.IAvnPredicateCallback redicateRef, Avalonia.Native.Interop.IAvnActionCallback callback) + { + System.IntPtr redicateRef_ = System.IntPtr.Zero; + System.IntPtr callback_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + redicateRef_ = SharpGen.Runtime.CppObject.ToCallbackPtr(redicateRef); + callback_ = SharpGen.Runtime.CppObject.ToCallbackPtr(callback); + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (void *)redicateRef_, (void *)callback_, (*(void ***)this._nativePointer)[6]); + System.GC.KeepAlive(redicateRef); + System.GC.KeepAlive(callback); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnMenuItem::SetIsChecked([In] bool isChecked) + /// IAvnMenuItem::SetIsChecked + internal unsafe void SetIsChecked(System.Boolean isChecked) + { + System.Byte isChecked_; + SharpGen.Runtime.Result __result__; + isChecked_ = (System.Byte)(isChecked ? 1 : 0); + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, isChecked_, (*(void ***)this._nativePointer)[7]); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnMenuItem::SetToggleType([In] AvnMenuItemToggleType toggleType) + /// IAvnMenuItem::SetToggleType + internal unsafe void SetToggleType(Avalonia.Native.Interop.AvnMenuItemToggleType toggleType) + { + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, unchecked ((System.Int32)toggleType), (*(void ***)this._nativePointer)[8]); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// No documentation. + /// HRESULT IAvnMenuItem::SetIcon([In] void* data,[In] size_t length) + /// IAvnMenuItem::SetIcon + public unsafe void SetIcon(System.IntPtr data, SharpGen.Runtime.PointerSize length) + { + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (void *)data, (void *)length, (*(void ***)this._nativePointer)[9]); + __result__.CheckError(); + } + } + + [System.Runtime.InteropServices.GuidAttribute("2e2cda0a-9ae5-4f1b-8e20-081a04279f20")] + public partial class IAvnNativeControlHost : SharpGen.Runtime.ComObject + { + public IAvnNativeControlHost(System.IntPtr nativePtr): base (nativePtr) + { + } + + public static explicit operator IAvnNativeControlHost(System.IntPtr nativePtr) => nativePtr == System.IntPtr.Zero ? null : new IAvnNativeControlHost(nativePtr); + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnNativeControlHost::CreateDefaultChild([In] void* parent,[Out] void** retOut) + /// IAvnNativeControlHost::CreateDefaultChild + public unsafe System.IntPtr CreateDefaultChild(System.IntPtr arentRef) + { + System.IntPtr retOut; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (void *)arentRef, &retOut, (*(void ***)this._nativePointer)[3]); + __result__.CheckError(); + return retOut; + } + + /// + /// No documentation. + /// + /// No documentation. + /// IAvnNativeControlHostTopLevelAttachment* IAvnNativeControlHost::CreateAttachment() + /// IAvnNativeControlHost::CreateAttachment + public unsafe Avalonia.Native.Interop.IAvnNativeControlHostTopLevelAttachment CreateAttachment() + { + Avalonia.Native.Interop.IAvnNativeControlHostTopLevelAttachment __result__; + System.IntPtr __result__native = System.IntPtr.Zero; + __result__native = Avalonia.Native.LocalInterop.CalliThisCallSystemIntPtr(this._nativePointer, (*(void ***)this._nativePointer)[4]); + if (__result__native != System.IntPtr.Zero) + __result__ = new Avalonia.Native.Interop.IAvnNativeControlHostTopLevelAttachment(__result__native); + else + __result__ = null; + return __result__; + } + + /// + /// No documentation. + /// + /// No documentation. + /// void IAvnNativeControlHost::DestroyDefaultChild([In] void* child) + /// IAvnNativeControlHost::DestroyDefaultChild + public unsafe void DestroyDefaultChild(System.IntPtr child) + { + Avalonia.Native.LocalInterop.CalliThisCallvoid(this._nativePointer, (void *)child, (*(void ***)this._nativePointer)[5]); + } + } + + [System.Runtime.InteropServices.GuidAttribute("2e2cda0a-9ae5-4f1b-8e20-081a04279f21")] + public partial class IAvnNativeControlHostTopLevelAttachment : SharpGen.Runtime.ComObject + { + public IAvnNativeControlHostTopLevelAttachment(System.IntPtr nativePtr): base (nativePtr) + { + } + + public static explicit operator IAvnNativeControlHostTopLevelAttachment(System.IntPtr nativePtr) => nativePtr == System.IntPtr.Zero ? null : new IAvnNativeControlHostTopLevelAttachment(nativePtr); + /// + /// No documentation. + /// + /// GetParentHandle + /// GetParentHandle + public System.IntPtr ParentHandle + { + get => GetParentHandle(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// void* IAvnNativeControlHostTopLevelAttachment::GetParentHandle() + /// IAvnNativeControlHostTopLevelAttachment::GetParentHandle + internal unsafe System.IntPtr GetParentHandle() + { + System.IntPtr __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallSystemIntPtr(this._nativePointer, (*(void ***)this._nativePointer)[3]); + return __result__; + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnNativeControlHostTopLevelAttachment::InitializeWithChildHandle([In] void* child) + /// IAvnNativeControlHostTopLevelAttachment::InitializeWithChildHandle + public unsafe void InitializeWithChildHandle(System.IntPtr child) + { + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (void *)child, (*(void ***)this._nativePointer)[4]); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnNativeControlHostTopLevelAttachment::AttachTo([In] IAvnNativeControlHost* host) + /// IAvnNativeControlHostTopLevelAttachment::AttachTo + public unsafe void AttachTo(Avalonia.Native.Interop.IAvnNativeControlHost host) + { + System.IntPtr host_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + host_ = SharpGen.Runtime.CppObject.ToCallbackPtr(host); + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (void *)host_, (*(void ***)this._nativePointer)[5]); + System.GC.KeepAlive(host); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// No documentation. + /// No documentation. + /// void IAvnNativeControlHostTopLevelAttachment::ShowInBounds([In] float x,[In] float y,[In] float width,[In] float height) + /// IAvnNativeControlHostTopLevelAttachment::ShowInBounds + public unsafe void ShowInBounds(System.Single x, System.Single y, System.Single width, System.Single height) + { + Avalonia.Native.LocalInterop.CalliThisCallvoid(this._nativePointer, x, y, width, height, (*(void ***)this._nativePointer)[6]); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// void IAvnNativeControlHostTopLevelAttachment::HideWithSize([In] float width,[In] float height) + /// IAvnNativeControlHostTopLevelAttachment::HideWithSize + public unsafe void HideWithSize(System.Single width, System.Single height) + { + Avalonia.Native.LocalInterop.CalliThisCallvoid(this._nativePointer, width, height, (*(void ***)this._nativePointer)[7]); + } + + /// + /// No documentation. + /// + /// void IAvnNativeControlHostTopLevelAttachment::ReleaseChild() + /// IAvnNativeControlHostTopLevelAttachment::ReleaseChild + public unsafe void ReleaseChild() + { + Avalonia.Native.LocalInterop.CalliThisCallvoid(this._nativePointer, (*(void ***)this._nativePointer)[8]); + } + } + + [System.Runtime.InteropServices.GuidAttribute("2e2cda0a-9ae5-4f1b-8e20-081a04279f0b")] + public partial class IAvnPlatformThreadingInterface : SharpGen.Runtime.ComObject + { + public IAvnPlatformThreadingInterface(System.IntPtr nativePtr): base (nativePtr) + { + } + + public static explicit operator IAvnPlatformThreadingInterface(System.IntPtr nativePtr) => nativePtr == System.IntPtr.Zero ? null : new IAvnPlatformThreadingInterface(nativePtr); + /// + /// No documentation. + /// + /// GetCurrentThreadIsLoopThread + /// GetCurrentThreadIsLoopThread + public System.Boolean CurrentThreadIsLoopThread + { + get => GetCurrentThreadIsLoopThread(); + } + + /// + /// No documentation. + /// + /// SetSignaledCallback + /// SetSignaledCallback + public Avalonia.Native.Interop.IAvnSignaledCallback SignaledCallback + { + set => SetSignaledCallback(value); + } + + /// + /// No documentation. + /// + /// No documentation. + /// bool IAvnPlatformThreadingInterface::GetCurrentThreadIsLoopThread() + /// IAvnPlatformThreadingInterface::GetCurrentThreadIsLoopThread + internal unsafe System.Boolean GetCurrentThreadIsLoopThread() + { + System.Boolean __result__; + System.Byte __result__native; + __result__native = Avalonia.Native.LocalInterop.CalliThisCallSystemByte(this._nativePointer, (*(void ***)this._nativePointer)[3]); + __result__ = __result__native != 0; + return __result__; + } + + /// + /// No documentation. + /// + /// No documentation. + /// void IAvnPlatformThreadingInterface::SetSignaledCallback([In] IAvnSignaledCallback* cb) + /// IAvnPlatformThreadingInterface::SetSignaledCallback + internal unsafe void SetSignaledCallback(Avalonia.Native.Interop.IAvnSignaledCallback cb) + { + System.IntPtr cb_ = System.IntPtr.Zero; + cb_ = SharpGen.Runtime.CppObject.ToCallbackPtr(cb); + Avalonia.Native.LocalInterop.CalliThisCallvoid(this._nativePointer, (void *)cb_, (*(void ***)this._nativePointer)[4]); + System.GC.KeepAlive(cb); + } + + /// + /// No documentation. + /// + /// No documentation. + /// IAvnLoopCancellation* IAvnPlatformThreadingInterface::CreateLoopCancellation() + /// IAvnPlatformThreadingInterface::CreateLoopCancellation + public unsafe Avalonia.Native.Interop.IAvnLoopCancellation CreateLoopCancellation() + { + Avalonia.Native.Interop.IAvnLoopCancellation __result__; + System.IntPtr __result__native = System.IntPtr.Zero; + __result__native = Avalonia.Native.LocalInterop.CalliThisCallSystemIntPtr(this._nativePointer, (*(void ***)this._nativePointer)[5]); + if (__result__native != System.IntPtr.Zero) + __result__ = new Avalonia.Native.Interop.IAvnLoopCancellation(__result__native); + else + __result__ = null; + return __result__; + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnPlatformThreadingInterface::RunLoop([In] IAvnLoopCancellation* cancel) + /// IAvnPlatformThreadingInterface::RunLoop + public unsafe void RunLoop(Avalonia.Native.Interop.IAvnLoopCancellation cancel) + { + System.IntPtr cancel_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + cancel_ = SharpGen.Runtime.CppObject.ToCallbackPtr(cancel); + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (void *)cancel_, (*(void ***)this._nativePointer)[6]); + System.GC.KeepAlive(cancel); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// void IAvnPlatformThreadingInterface::Signal([In] int priority) + /// IAvnPlatformThreadingInterface::Signal + public unsafe void Signal(System.Int32 priority) + { + Avalonia.Native.LocalInterop.CalliThisCallvoid(this._nativePointer, priority, (*(void ***)this._nativePointer)[7]); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// No documentation. + /// No documentation. + /// IUnknown* IAvnPlatformThreadingInterface::StartTimer([In] int priority,[In] int ms,[In] IAvnActionCallback* callback) + /// IAvnPlatformThreadingInterface::StartTimer + public unsafe SharpGen.Runtime.ComObject StartTimer(System.Int32 priority, System.Int32 ms, Avalonia.Native.Interop.IAvnActionCallback callback) + { + System.IntPtr callback_ = System.IntPtr.Zero; + SharpGen.Runtime.ComObject __result__; + System.IntPtr __result__native = System.IntPtr.Zero; + callback_ = SharpGen.Runtime.CppObject.ToCallbackPtr(callback); + __result__native = Avalonia.Native.LocalInterop.CalliThisCallSystemIntPtr(this._nativePointer, priority, ms, (void *)callback_, (*(void ***)this._nativePointer)[8]); + if (__result__native != System.IntPtr.Zero) + __result__ = new SharpGen.Runtime.ComObject(__result__native); + else + __result__ = null; + System.GC.KeepAlive(callback); + return __result__; + } + } + + [System.Runtime.InteropServices.GuidAttribute("2e2cda0a-9ae5-4f1b-8e20-081a04279f03")] + public partial class IAvnPopup : Avalonia.Native.Interop.IAvnWindowBase + { + public IAvnPopup(System.IntPtr nativePtr): base (nativePtr) + { + } + + public static explicit operator IAvnPopup(System.IntPtr nativePtr) => nativePtr == System.IntPtr.Zero ? null : new IAvnPopup(nativePtr); + } + + class IAvnPredicateCallbackShadow : SharpGen.Runtime.ComObjectShadow + { + protected unsafe class IAvnPredicateCallbackVtbl : SharpGen.Runtime.ComObjectShadow.ComObjectVtbl + { + public IAvnPredicateCallbackVtbl(int numberOfCallbackMethods): base (numberOfCallbackMethods + 1) + { + AddMethod(new EvaluateDelegate(Evaluate)); + } + + [System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(System.Runtime.InteropServices.CallingConvention.ThisCall)] + private delegate System.Byte EvaluateDelegate(System.IntPtr thisObject); + private static unsafe System.Byte Evaluate(System.IntPtr thisObject) + { + try + { + System.Boolean __result__ = default (System.Boolean); + System.Byte __result__native; + IAvnPredicateCallback @this = (IAvnPredicateCallback)ToShadow(thisObject).Callback; + __result__ = @this.Evaluate(); + __result__native = (System.Byte)(__result__ ? 1 : 0); + return __result__native; + } + catch (System.Exception __exception__) + { + IAvnPredicateCallback @this = (IAvnPredicateCallback)ToShadow(thisObject).Callback; + (@this as SharpGen.Runtime.IExceptionCallback)?.RaiseException(__exception__); + return default (System.Byte); + } + } + } + + protected override SharpGen.Runtime.CppObjectVtbl Vtbl + { + get; + } + + = new Avalonia.Native.Interop.IAvnPredicateCallbackShadow.IAvnPredicateCallbackVtbl(0); + } + + [System.Runtime.InteropServices.GuidAttribute("2e2cda0a-9ae5-4f1b-8e20-081a04279f18"), SharpGen.Runtime.ShadowAttribute(typeof (Avalonia.Native.Interop.IAvnPredicateCallbackShadow))] + public partial interface IAvnPredicateCallback : SharpGen.Runtime.IUnknown + { + System.Boolean Evaluate(); + } + + [System.Runtime.InteropServices.GuidAttribute("2e2cda0a-9ae5-4f1b-8e20-081a04279f0e")] + public partial class IAvnScreens : SharpGen.Runtime.ComObject + { + public IAvnScreens(System.IntPtr nativePtr): base (nativePtr) + { + } + + public static explicit operator IAvnScreens(System.IntPtr nativePtr) => nativePtr == System.IntPtr.Zero ? null : new IAvnScreens(nativePtr); + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvnScreens::GetScreenCount([In] int* ret) + /// IAvnScreens::GetScreenCount + public unsafe System.Int32 GetScreenCount() + { + System.Int32 ret; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, &ret, (*(void ***)this._nativePointer)[3]); + __result__.CheckError(); + return ret; + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnScreens::GetScreen([In] int index,[In] AvnScreen* ret) + /// IAvnScreens::GetScreen + public unsafe Avalonia.Native.Interop.AvnScreen GetScreen(System.Int32 index) + { + Avalonia.Native.Interop.AvnScreen ret; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, index, &ret, (*(void ***)this._nativePointer)[4]); + __result__.CheckError(); + return ret; + } + } + + class IAvnSignaledCallbackShadow : SharpGen.Runtime.ComObjectShadow + { + protected unsafe class IAvnSignaledCallbackVtbl : SharpGen.Runtime.ComObjectShadow.ComObjectVtbl + { + public IAvnSignaledCallbackVtbl(int numberOfCallbackMethods): base (numberOfCallbackMethods + 1) + { + AddMethod(new SignaledDelegate(Signaled)); + } + + [System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(System.Runtime.InteropServices.CallingConvention.ThisCall)] + private delegate void SignaledDelegate(System.IntPtr thisObject, int arg0, System.Byte arg1); + private static unsafe void Signaled(System.IntPtr thisObject, int param0, System.Byte param1) + { + try + { + System.Int32 priority = default (System.Int32); + priority = (System.Int32)param0; + System.Boolean priorityContainsMeaningfulValue = default (System.Boolean); + System.Byte priorityContainsMeaningfulValue_ = (System.Byte)param1; + IAvnSignaledCallback @this = (IAvnSignaledCallback)ToShadow(thisObject).Callback; + priorityContainsMeaningfulValue = priorityContainsMeaningfulValue_ != 0; + @this.Signaled(priority, priorityContainsMeaningfulValue); + } + catch (System.Exception __exception__) + { + IAvnSignaledCallback @this = (IAvnSignaledCallback)ToShadow(thisObject).Callback; + (@this as SharpGen.Runtime.IExceptionCallback)?.RaiseException(__exception__); + } + } + } + + protected override SharpGen.Runtime.CppObjectVtbl Vtbl + { + get; + } + + = new Avalonia.Native.Interop.IAvnSignaledCallbackShadow.IAvnSignaledCallbackVtbl(0); + } + + [System.Runtime.InteropServices.GuidAttribute("2e2cda0a-9ae5-4f1b-8e20-081a04279f09"), SharpGen.Runtime.ShadowAttribute(typeof (Avalonia.Native.Interop.IAvnSignaledCallbackShadow))] + public partial interface IAvnSignaledCallback : SharpGen.Runtime.IUnknown + { + void Signaled(System.Int32 priority, System.Boolean priorityContainsMeaningfulValue); + } + + [System.Runtime.InteropServices.GuidAttribute("2e2cda0a-9ae5-4f1b-8e20-081a04279f17")] + public partial class IAvnString : SharpGen.Runtime.ComObject + { + public IAvnString(System.IntPtr nativePtr): base (nativePtr) + { + } + + public static explicit operator IAvnString(System.IntPtr nativePtr) => nativePtr == System.IntPtr.Zero ? null : new IAvnString(nativePtr); + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvnString::Pointer([Out] void** retOut) + /// IAvnString::Pointer + public unsafe System.IntPtr Pointer() + { + System.IntPtr retOut; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, &retOut, (*(void ***)this._nativePointer)[3]); + __result__.CheckError(); + return retOut; + } + + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvnString::Length([In] int* ret) + /// IAvnString::Length + public unsafe System.Int32 Length() + { + System.Int32 ret; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, &ret, (*(void ***)this._nativePointer)[4]); + __result__.CheckError(); + return ret; + } + } + + [System.Runtime.InteropServices.GuidAttribute("2e2cda0a-9ae5-4f1b-8e20-081a04279f20")] + public partial class IAvnStringArray : SharpGen.Runtime.ComObject + { + public IAvnStringArray(System.IntPtr nativePtr): base (nativePtr) + { + } + + public static explicit operator IAvnStringArray(System.IntPtr nativePtr) => nativePtr == System.IntPtr.Zero ? null : new IAvnStringArray(nativePtr); + /// + /// No documentation. + /// + /// GetCount + /// GetCount + public System.UInt32 Count + { + get => GetCount(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// unsigned int IAvnStringArray::GetCount() + /// IAvnStringArray::GetCount + internal unsafe System.UInt32 GetCount() + { + System.UInt32 __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallSystemUInt32(this._nativePointer, (*(void ***)this._nativePointer)[3]); + return __result__; + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnStringArray::Get([In] unsigned int index,[In] IAvnString** ppv) + /// IAvnStringArray::Get + public unsafe Avalonia.Native.Interop.IAvnString Get(System.UInt32 index) + { + Avalonia.Native.Interop.IAvnString vOut; + System.IntPtr vOut_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, index, &vOut_, (*(void ***)this._nativePointer)[4]); + if (vOut_ != System.IntPtr.Zero) + vOut = new Avalonia.Native.Interop.IAvnString(vOut_); + else + vOut = null; + __result__.CheckError(); + return vOut; + } + } + + class IAvnSystemDialogEventsShadow : SharpGen.Runtime.ComObjectShadow + { + protected unsafe class IAvnSystemDialogEventsVtbl : SharpGen.Runtime.ComObjectShadow.ComObjectVtbl + { + public IAvnSystemDialogEventsVtbl(int numberOfCallbackMethods): base (numberOfCallbackMethods + 1) + { + AddMethod(new OnCompletedDelegate(OnCompleted)); + } + + [System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(System.Runtime.InteropServices.CallingConvention.ThisCall)] + private delegate void OnCompletedDelegate(System.IntPtr thisObject, int arg0, void *arg1); + private static unsafe void OnCompleted(System.IntPtr thisObject, int param0, void *param1) + { + try + { + System.Int32 numResults = default (System.Int32); + numResults = (System.Int32)param0; + System.IntPtr trFirstResultRef = default (System.IntPtr); + trFirstResultRef = (System.IntPtr)param1; + IAvnSystemDialogEvents @this = (IAvnSystemDialogEvents)ToShadow(thisObject).Callback; + @this.OnCompleted(numResults, trFirstResultRef); + } + catch (System.Exception __exception__) + { + IAvnSystemDialogEvents @this = (IAvnSystemDialogEvents)ToShadow(thisObject).Callback; + (@this as SharpGen.Runtime.IExceptionCallback)?.RaiseException(__exception__); + } + } + } + + protected override SharpGen.Runtime.CppObjectVtbl Vtbl + { + get; + } + + = new Avalonia.Native.Interop.IAvnSystemDialogEventsShadow.IAvnSystemDialogEventsVtbl(0); + } + + [System.Runtime.InteropServices.GuidAttribute("2e2cda0a-9ae5-4f1b-8e20-081a04279f0c"), SharpGen.Runtime.ShadowAttribute(typeof (Avalonia.Native.Interop.IAvnSystemDialogEventsShadow))] + public partial interface IAvnSystemDialogEvents : SharpGen.Runtime.IUnknown + { + void OnCompleted(System.Int32 numResults, System.IntPtr trFirstResultRef); + } + + [System.Runtime.InteropServices.GuidAttribute("2e2cda0a-9ae5-4f1b-8e20-081a04279f0d")] + public partial class IAvnSystemDialogs : SharpGen.Runtime.ComObject + { + public IAvnSystemDialogs(System.IntPtr nativePtr): base (nativePtr) + { + } + + public static explicit operator IAvnSystemDialogs(System.IntPtr nativePtr) => nativePtr == System.IntPtr.Zero ? null : new IAvnSystemDialogs(nativePtr); + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// No documentation. + /// No documentation. + /// void IAvnSystemDialogs::SelectFolderDialog([In] IAvnWindow* parentWindowHandle,[In] IAvnSystemDialogEvents* events,[In] const char* title,[In] const char* initialPath) + /// IAvnSystemDialogs::SelectFolderDialog + public unsafe void SelectFolderDialog(Avalonia.Native.Interop.IAvnWindow arentWindowHandleRef, Avalonia.Native.Interop.IAvnSystemDialogEvents events, System.String title, System.String initialPath) + { + System.IntPtr arentWindowHandleRef_ = System.IntPtr.Zero; + System.IntPtr events_ = System.IntPtr.Zero; + System.IntPtr title_; + System.IntPtr initialPath_; + arentWindowHandleRef_ = SharpGen.Runtime.CppObject.ToCallbackPtr(arentWindowHandleRef); + events_ = SharpGen.Runtime.CppObject.ToCallbackPtr(events); + title_ = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(title); + initialPath_ = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(initialPath); + Avalonia.Native.LocalInterop.CalliThisCallvoid(this._nativePointer, (void *)arentWindowHandleRef_, (void *)events_, (void *)title_, (void *)initialPath_, (*(void ***)this._nativePointer)[3]); + System.GC.KeepAlive(arentWindowHandleRef); + System.GC.KeepAlive(events); + System.Runtime.InteropServices.Marshal.FreeHGlobal(title_); + System.Runtime.InteropServices.Marshal.FreeHGlobal(initialPath_); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// No documentation. + /// No documentation. + /// No documentation. + /// No documentation. + /// No documentation. + /// void IAvnSystemDialogs::OpenFileDialog([In] IAvnWindow* parentWindowHandle,[In] IAvnSystemDialogEvents* events,[In] bool allowMultiple,[In] const char* title,[In] const char* initialDirectory,[In] const char* initialFile,[In] const char* filters) + /// IAvnSystemDialogs::OpenFileDialog + public unsafe void OpenFileDialog(Avalonia.Native.Interop.IAvnWindow arentWindowHandleRef, Avalonia.Native.Interop.IAvnSystemDialogEvents events, System.Boolean allowMultiple, System.String title, System.String initialDirectory, System.String initialFile, System.String filters) + { + System.IntPtr arentWindowHandleRef_ = System.IntPtr.Zero; + System.IntPtr events_ = System.IntPtr.Zero; + System.Byte allowMultiple_; + System.IntPtr title_; + System.IntPtr initialDirectory_; + System.IntPtr initialFile_; + System.IntPtr filters_; + arentWindowHandleRef_ = SharpGen.Runtime.CppObject.ToCallbackPtr(arentWindowHandleRef); + events_ = SharpGen.Runtime.CppObject.ToCallbackPtr(events); + allowMultiple_ = (System.Byte)(allowMultiple ? 1 : 0); + title_ = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(title); + initialDirectory_ = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(initialDirectory); + initialFile_ = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(initialFile); + filters_ = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(filters); + Avalonia.Native.LocalInterop.CalliThisCallvoid(this._nativePointer, (void *)arentWindowHandleRef_, (void *)events_, allowMultiple_, (void *)title_, (void *)initialDirectory_, (void *)initialFile_, (void *)filters_, (*(void ***)this._nativePointer)[4]); + System.GC.KeepAlive(arentWindowHandleRef); + System.GC.KeepAlive(events); + System.Runtime.InteropServices.Marshal.FreeHGlobal(title_); + System.Runtime.InteropServices.Marshal.FreeHGlobal(initialDirectory_); + System.Runtime.InteropServices.Marshal.FreeHGlobal(initialFile_); + System.Runtime.InteropServices.Marshal.FreeHGlobal(filters_); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// No documentation. + /// No documentation. + /// No documentation. + /// No documentation. + /// void IAvnSystemDialogs::SaveFileDialog([In] IAvnWindow* parentWindowHandle,[In] IAvnSystemDialogEvents* events,[In] const char* title,[In] const char* initialDirectory,[In] const char* initialFile,[In] const char* filters) + /// IAvnSystemDialogs::SaveFileDialog + public unsafe void SaveFileDialog(Avalonia.Native.Interop.IAvnWindow arentWindowHandleRef, Avalonia.Native.Interop.IAvnSystemDialogEvents events, System.String title, System.String initialDirectory, System.String initialFile, System.String filters) + { + System.IntPtr arentWindowHandleRef_ = System.IntPtr.Zero; + System.IntPtr events_ = System.IntPtr.Zero; + System.IntPtr title_; + System.IntPtr initialDirectory_; + System.IntPtr initialFile_; + System.IntPtr filters_; + arentWindowHandleRef_ = SharpGen.Runtime.CppObject.ToCallbackPtr(arentWindowHandleRef); + events_ = SharpGen.Runtime.CppObject.ToCallbackPtr(events); + title_ = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(title); + initialDirectory_ = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(initialDirectory); + initialFile_ = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(initialFile); + filters_ = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(filters); + Avalonia.Native.LocalInterop.CalliThisCallvoid(this._nativePointer, (void *)arentWindowHandleRef_, (void *)events_, (void *)title_, (void *)initialDirectory_, (void *)initialFile_, (void *)filters_, (*(void ***)this._nativePointer)[5]); + System.GC.KeepAlive(arentWindowHandleRef); + System.GC.KeepAlive(events); + System.Runtime.InteropServices.Marshal.FreeHGlobal(title_); + System.Runtime.InteropServices.Marshal.FreeHGlobal(initialDirectory_); + System.Runtime.InteropServices.Marshal.FreeHGlobal(initialFile_); + System.Runtime.InteropServices.Marshal.FreeHGlobal(filters_); + } + } + + [System.Runtime.InteropServices.GuidAttribute("2e2cda0a-9ae5-4f1b-8e20-081a04279f04")] + public partial class IAvnWindow : Avalonia.Native.Interop.IAvnWindowBase + { + public IAvnWindow(System.IntPtr nativePtr): base (nativePtr) + { + } + + public static explicit operator IAvnWindow(System.IntPtr nativePtr) => nativePtr == System.IntPtr.Zero ? null : new IAvnWindow(nativePtr); + /// + /// No documentation. + /// + /// SetEnabled + /// SetEnabled + public System.Boolean Enabled + { + set => SetEnabled(value); + } + + /// + /// No documentation. + /// + /// SetParent + /// SetParent + public Avalonia.Native.Interop.IAvnWindow Parent + { + set => SetParent(value); + } + + /// + /// No documentation. + /// + /// SetCanResize + /// SetCanResize + public System.Boolean CanResize + { + set => SetCanResize(value); + } + + /// + /// No documentation. + /// + /// SetDecorations + /// SetDecorations + public Avalonia.Native.Interop.SystemDecorations Decorations + { + set => SetDecorations(value); + } + + /// + /// No documentation. + /// + /// SetTitle + /// SetTitle + public System.IntPtr Title + { + set => SetTitle(value); + } + + /// + /// No documentation. + /// + /// SetTitleBarColor + /// SetTitleBarColor + public Avalonia.Native.Interop.AvnColor TitleBarColor + { + set => SetTitleBarColor(value); + } + + /// + /// No documentation. + /// + /// SetExtendClientArea + /// SetExtendClientArea + public System.Boolean ExtendClientArea + { + set => SetExtendClientArea(value); + } + + /// + /// No documentation. + /// + /// SetExtendClientAreaHints + /// SetExtendClientAreaHints + public Avalonia.Native.Interop.AvnExtendClientAreaChromeHints ExtendClientAreaHints + { + set => SetExtendClientAreaHints(value); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnWindow::SetEnabled([In] bool enable) + /// IAvnWindow::SetEnabled + internal unsafe void SetEnabled(System.Boolean enable) + { + System.Byte enable_; + SharpGen.Runtime.Result __result__; + enable_ = (System.Byte)(enable ? 1 : 0); + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, enable_, (*(void ***)this._nativePointer)[30]); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnWindow::SetParent([In] IAvnWindow* parent) + /// IAvnWindow::SetParent + internal unsafe void SetParent(Avalonia.Native.Interop.IAvnWindow arentRef) + { + System.IntPtr arentRef_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + arentRef_ = SharpGen.Runtime.CppObject.ToCallbackPtr(arentRef); + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (void *)arentRef_, (*(void ***)this._nativePointer)[31]); + System.GC.KeepAlive(arentRef); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnWindow::SetCanResize([In] bool value) + /// IAvnWindow::SetCanResize + internal unsafe void SetCanResize(System.Boolean value) + { + System.Byte value_; + SharpGen.Runtime.Result __result__; + value_ = (System.Byte)(value ? 1 : 0); + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, value_, (*(void ***)this._nativePointer)[32]); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnWindow::SetDecorations([In] SystemDecorations value) + /// IAvnWindow::SetDecorations + internal unsafe void SetDecorations(Avalonia.Native.Interop.SystemDecorations value) + { + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, unchecked ((System.Int32)value), (*(void ***)this._nativePointer)[33]); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnWindow::SetTitle([In] void* utf8Title) + /// IAvnWindow::SetTitle + internal unsafe void SetTitle(System.IntPtr utf8Title) + { + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (void *)utf8Title, (*(void ***)this._nativePointer)[34]); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnWindow::SetTitleBarColor([In] AvnColor color) + /// IAvnWindow::SetTitleBarColor + internal unsafe void SetTitleBarColor(Avalonia.Native.Interop.AvnColor color) + { + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint0(this._nativePointer, color, (*(void ***)this._nativePointer)[35]); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnWindow::SetWindowState([In] AvnWindowState state) + /// IAvnWindow::SetWindowState + public unsafe void SetWindowState(Avalonia.Native.Interop.AvnWindowState state) + { + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, unchecked ((System.Int32)state), (*(void ***)this._nativePointer)[36]); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvnWindow::GetWindowState([In] AvnWindowState* ret) + /// IAvnWindow::GetWindowState + public unsafe Avalonia.Native.Interop.AvnWindowState GetWindowState() + { + Avalonia.Native.Interop.AvnWindowState ret; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, &ret, (*(void ***)this._nativePointer)[37]); + __result__.CheckError(); + return ret; + } + + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvnWindow::TakeFocusFromChildren() + /// IAvnWindow::TakeFocusFromChildren + public unsafe void TakeFocusFromChildren() + { + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (*(void ***)this._nativePointer)[38]); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnWindow::SetExtendClientArea([In] bool enable) + /// IAvnWindow::SetExtendClientArea + internal unsafe void SetExtendClientArea(System.Boolean enable) + { + System.Byte enable_; + SharpGen.Runtime.Result __result__; + enable_ = (System.Byte)(enable ? 1 : 0); + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, enable_, (*(void ***)this._nativePointer)[39]); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnWindow::SetExtendClientAreaHints([In] AvnExtendClientAreaChromeHints hints) + /// IAvnWindow::SetExtendClientAreaHints + internal unsafe void SetExtendClientAreaHints(Avalonia.Native.Interop.AvnExtendClientAreaChromeHints hints) + { + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, unchecked ((System.Int32)hints), (*(void ***)this._nativePointer)[40]); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvnWindow::GetExtendTitleBarHeight([In] double* ret) + /// IAvnWindow::GetExtendTitleBarHeight + public unsafe System.Double GetExtendTitleBarHeight() + { + System.Double ret; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, &ret, (*(void ***)this._nativePointer)[41]); + __result__.CheckError(); + return ret; + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnWindow::SetExtendTitleBarHeight([In] double value) + /// IAvnWindow::SetExtendTitleBarHeight + public unsafe void SetExtendTitleBarHeight(System.Double value) + { + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, value, (*(void ***)this._nativePointer)[42]); + __result__.CheckError(); + } + } + + [System.Runtime.InteropServices.GuidAttribute("2e2cda0a-9ae5-4f1b-8e20-081a04279f02")] + public partial class IAvnWindowBase : SharpGen.Runtime.ComObject + { + public IAvnWindowBase(System.IntPtr nativePtr): base (nativePtr) + { + } + + public static explicit operator IAvnWindowBase(System.IntPtr nativePtr) => nativePtr == System.IntPtr.Zero ? null : new IAvnWindowBase(nativePtr); + /// + /// No documentation. + /// + /// SetTopMost + /// SetTopMost + public System.Boolean TopMost + { + set => SetTopMost(value); + } + + /// + /// No documentation. + /// + /// SetCursor + /// SetCursor + public Avalonia.Native.Interop.IAvnCursor Cursor + { + set => SetCursor(value); + } + + /// + /// No documentation. + /// + /// SetMainMenu + /// SetMainMenu + public Avalonia.Native.Interop.IAvnMenu MainMenu + { + set => SetMainMenu(value); + } + + /// + /// No documentation. + /// + /// SetBlurEnabled + /// SetBlurEnabled + public System.Boolean BlurEnabled + { + set => SetBlurEnabled(value); + } + + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvnWindowBase::Show() + /// IAvnWindowBase::Show + public unsafe void Show() + { + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (*(void ***)this._nativePointer)[3]); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvnWindowBase::Hide() + /// IAvnWindowBase::Hide + public unsafe void Hide() + { + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (*(void ***)this._nativePointer)[4]); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvnWindowBase::Close() + /// IAvnWindowBase::Close + public unsafe void Close() + { + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (*(void ***)this._nativePointer)[5]); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvnWindowBase::Activate() + /// IAvnWindowBase::Activate + public unsafe void Activate() + { + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (*(void ***)this._nativePointer)[6]); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvnWindowBase::GetClientSize([In] AvnSize* ret) + /// IAvnWindowBase::GetClientSize + public unsafe Avalonia.Native.Interop.AvnSize GetClientSize() + { + Avalonia.Native.Interop.AvnSize ret; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, &ret, (*(void ***)this._nativePointer)[7]); + __result__.CheckError(); + return ret; + } + + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvnWindowBase::GetScaling([In] double* ret) + /// IAvnWindowBase::GetScaling + public unsafe System.Double GetScaling() + { + System.Double ret; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, &ret, (*(void ***)this._nativePointer)[8]); + __result__.CheckError(); + return ret; + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// No documentation. + /// HRESULT IAvnWindowBase::SetMinMaxSize([In] AvnSize minSize,[In] AvnSize maxSize) + /// IAvnWindowBase::SetMinMaxSize + public unsafe void SetMinMaxSize(Avalonia.Native.Interop.AvnSize minSize, Avalonia.Native.Interop.AvnSize maxSize) + { + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint0(this._nativePointer, minSize, maxSize, (*(void ***)this._nativePointer)[9]); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// No documentation. + /// HRESULT IAvnWindowBase::Resize([In] double width,[In] double height) + /// IAvnWindowBase::Resize + public unsafe void Resize(System.Double width, System.Double height) + { + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, width, height, (*(void ***)this._nativePointer)[10]); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnWindowBase::Invalidate([In] AvnRect rect) + /// IAvnWindowBase::Invalidate + public unsafe void Invalidate(Avalonia.Native.Interop.AvnRect rect) + { + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint0(this._nativePointer, rect, (*(void ***)this._nativePointer)[11]); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvnWindowBase::BeginMoveDrag() + /// IAvnWindowBase::BeginMoveDrag + public unsafe void BeginMoveDrag() + { + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (*(void ***)this._nativePointer)[12]); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnWindowBase::BeginResizeDrag([In] AvnWindowEdge edge) + /// IAvnWindowBase::BeginResizeDrag + public unsafe void BeginResizeDrag(Avalonia.Native.Interop.AvnWindowEdge edge) + { + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, unchecked ((System.Int32)edge), (*(void ***)this._nativePointer)[13]); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvnWindowBase::GetPosition([In] AvnPoint* ret) + /// IAvnWindowBase::GetPosition + public unsafe Avalonia.Native.Interop.AvnPoint GetPosition() + { + Avalonia.Native.Interop.AvnPoint ret; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, &ret, (*(void ***)this._nativePointer)[14]); + __result__.CheckError(); + return ret; + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnWindowBase::SetPosition([In] AvnPoint point) + /// IAvnWindowBase::SetPosition + public unsafe void SetPosition(Avalonia.Native.Interop.AvnPoint point) + { + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint0(this._nativePointer, point, (*(void ***)this._nativePointer)[15]); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnWindowBase::PointToClient([In] AvnPoint point,[In] AvnPoint* ret) + /// IAvnWindowBase::PointToClient + public unsafe Avalonia.Native.Interop.AvnPoint PointToClient(Avalonia.Native.Interop.AvnPoint point) + { + Avalonia.Native.Interop.AvnPoint ret; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint0(this._nativePointer, point, &ret, (*(void ***)this._nativePointer)[16]); + __result__.CheckError(); + return ret; + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnWindowBase::PointToScreen([In] AvnPoint point,[In] AvnPoint* ret) + /// IAvnWindowBase::PointToScreen + public unsafe Avalonia.Native.Interop.AvnPoint PointToScreen(Avalonia.Native.Interop.AvnPoint point) + { + Avalonia.Native.Interop.AvnPoint ret; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint0(this._nativePointer, point, &ret, (*(void ***)this._nativePointer)[17]); + __result__.CheckError(); + return ret; + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// No documentation. + /// HRESULT IAvnWindowBase::ThreadSafeSetSwRenderedFrame([In] AvnFramebuffer* fb,[In] IUnknown* dispose) + /// IAvnWindowBase::ThreadSafeSetSwRenderedFrame + public unsafe void ThreadSafeSetSwRenderedFrame(ref Avalonia.Native.Interop.AvnFramebuffer fb, SharpGen.Runtime.IUnknown dispose) + { + System.IntPtr dispose_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + dispose_ = SharpGen.Runtime.CppObject.ToCallbackPtr(dispose); + fixed (void *fb_ = &fb) + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, fb_, (void *)dispose_, (*(void ***)this._nativePointer)[18]); + System.GC.KeepAlive(dispose); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnWindowBase::SetTopMost([In] bool value) + /// IAvnWindowBase::SetTopMost + internal unsafe void SetTopMost(System.Boolean value) + { + System.Byte value_; + SharpGen.Runtime.Result __result__; + value_ = (System.Byte)(value ? 1 : 0); + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, value_, (*(void ***)this._nativePointer)[19]); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnWindowBase::SetCursor([In] IAvnCursor* cursor) + /// IAvnWindowBase::SetCursor + internal unsafe void SetCursor(Avalonia.Native.Interop.IAvnCursor cursor) + { + System.IntPtr cursor_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + cursor_ = SharpGen.Runtime.CppObject.ToCallbackPtr(cursor); + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (void *)cursor_, (*(void ***)this._nativePointer)[20]); + System.GC.KeepAlive(cursor); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvnWindowBase::CreateGlRenderTarget([In] IAvnGlSurfaceRenderTarget** ret) + /// IAvnWindowBase::CreateGlRenderTarget + public unsafe Avalonia.Native.Interop.IAvnGlSurfaceRenderTarget CreateGlRenderTarget() + { + Avalonia.Native.Interop.IAvnGlSurfaceRenderTarget ret; + System.IntPtr ret_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, &ret_, (*(void ***)this._nativePointer)[21]); + if (ret_ != System.IntPtr.Zero) + ret = new Avalonia.Native.Interop.IAvnGlSurfaceRenderTarget(ret_); + else + ret = null; + __result__.CheckError(); + return ret; + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnWindowBase::SetMainMenu([In] IAvnMenu* menu) + /// IAvnWindowBase::SetMainMenu + internal unsafe void SetMainMenu(Avalonia.Native.Interop.IAvnMenu menu) + { + System.IntPtr menu_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + menu_ = SharpGen.Runtime.CppObject.ToCallbackPtr(menu); + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, (void *)menu_, (*(void ***)this._nativePointer)[22]); + System.GC.KeepAlive(menu); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvnWindowBase::ObtainNSWindowHandle([Out] void** retOut) + /// IAvnWindowBase::ObtainNSWindowHandle + public unsafe System.IntPtr ObtainNSWindowHandle() + { + System.IntPtr retOut; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, &retOut, (*(void ***)this._nativePointer)[23]); + __result__.CheckError(); + return retOut; + } + + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvnWindowBase::ObtainNSWindowHandleRetained([Out] void** retOut) + /// IAvnWindowBase::ObtainNSWindowHandleRetained + public unsafe System.IntPtr ObtainNSWindowHandleRetained() + { + System.IntPtr retOut; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, &retOut, (*(void ***)this._nativePointer)[24]); + __result__.CheckError(); + return retOut; + } + + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvnWindowBase::ObtainNSViewHandle([Out] void** retOut) + /// IAvnWindowBase::ObtainNSViewHandle + public unsafe System.IntPtr ObtainNSViewHandle() + { + System.IntPtr retOut; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, &retOut, (*(void ***)this._nativePointer)[25]); + __result__.CheckError(); + return retOut; + } + + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvnWindowBase::ObtainNSViewHandleRetained([Out] void** retOut) + /// IAvnWindowBase::ObtainNSViewHandleRetained + public unsafe System.IntPtr ObtainNSViewHandleRetained() + { + System.IntPtr retOut; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, &retOut, (*(void ***)this._nativePointer)[26]); + __result__.CheckError(); + return retOut; + } + + /// + /// No documentation. + /// + /// No documentation. + /// HRESULT IAvnWindowBase::CreateNativeControlHost([Out] IAvnNativeControlHost** retOut) + /// IAvnWindowBase::CreateNativeControlHost + public unsafe Avalonia.Native.Interop.IAvnNativeControlHost CreateNativeControlHost() + { + Avalonia.Native.Interop.IAvnNativeControlHost retOut; + System.IntPtr retOut_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, &retOut_, (*(void ***)this._nativePointer)[27]); + if (retOut_ != System.IntPtr.Zero) + retOut = new Avalonia.Native.Interop.IAvnNativeControlHost(retOut_); + else + retOut = null; + __result__.CheckError(); + return retOut; + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// No documentation. + /// No documentation. + /// No documentation. + /// No documentation. + /// HRESULT IAvnWindowBase::BeginDragAndDropOperation([In] AvnDragDropEffects effects,[In] AvnPoint point,[In] IAvnClipboard* clipboard,[In] IAvnDndResultCallback* cb,[In] void* sourceHandle) + /// IAvnWindowBase::BeginDragAndDropOperation + public unsafe void BeginDragAndDropOperation(Avalonia.Native.Interop.AvnDragDropEffects effects, Avalonia.Native.Interop.AvnPoint point, Avalonia.Native.Interop.IAvnClipboard clipboard, Avalonia.Native.Interop.IAvnDndResultCallback cb, System.IntPtr sourceHandle) + { + System.IntPtr clipboard_ = System.IntPtr.Zero; + System.IntPtr cb_ = System.IntPtr.Zero; + SharpGen.Runtime.Result __result__; + clipboard_ = SharpGen.Runtime.CppObject.ToCallbackPtr(clipboard); + cb_ = SharpGen.Runtime.CppObject.ToCallbackPtr(cb); + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint0(this._nativePointer, unchecked ((System.Int32)effects), point, (void *)clipboard_, (void *)cb_, (void *)sourceHandle, (*(void ***)this._nativePointer)[28]); + System.GC.KeepAlive(clipboard); + System.GC.KeepAlive(cb); + __result__.CheckError(); + } + + /// + /// No documentation. + /// + /// No documentation. + /// No documentation. + /// HRESULT IAvnWindowBase::SetBlurEnabled([In] bool enable) + /// IAvnWindowBase::SetBlurEnabled + internal unsafe void SetBlurEnabled(System.Boolean enable) + { + System.Byte enable_; + SharpGen.Runtime.Result __result__; + enable_ = (System.Byte)(enable ? 1 : 0); + __result__ = Avalonia.Native.LocalInterop.CalliThisCallint(this._nativePointer, enable_, (*(void ***)this._nativePointer)[29]); + __result__.CheckError(); + } + } + + class IAvnWindowBaseEventsShadow : SharpGen.Runtime.ComObjectShadow + { + protected unsafe class IAvnWindowBaseEventsVtbl : SharpGen.Runtime.ComObjectShadow.ComObjectVtbl + { + public IAvnWindowBaseEventsVtbl(int numberOfCallbackMethods): base (numberOfCallbackMethods + 13) + { + AddMethod(new PaintDelegate(Paint)); + AddMethod(new ClosedDelegate(Closed)); + AddMethod(new ActivatedDelegate(Activated)); + AddMethod(new DeactivatedDelegate(Deactivated)); + AddMethod(new ResizedDelegate(Resized)); + AddMethod(new PositionChangedDelegate(PositionChanged)); + AddMethod(new RawMouseEventDelegate(RawMouseEvent)); + AddMethod(new RawKeyEventDelegate(RawKeyEvent)); + AddMethod(new RawTextInputEventDelegate(RawTextInputEvent)); + AddMethod(new ScalingChangedDelegate(ScalingChanged)); + AddMethod(new RunRenderPriorityJobsDelegate(RunRenderPriorityJobs)); + AddMethod(new LostFocusDelegate(LostFocus)); + AddMethod(new DragEventDelegate(DragEvent)); + } + + [System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(System.Runtime.InteropServices.CallingConvention.ThisCall)] + private delegate int PaintDelegate(System.IntPtr thisObject); + private static unsafe int Paint(System.IntPtr thisObject) + { + try + { + IAvnWindowBaseEvents @this = (IAvnWindowBaseEvents)ToShadow(thisObject).Callback; + @this.Paint(); + return SharpGen.Runtime.Result.Ok.Code; + } + catch (System.Exception __exception__) + { + IAvnWindowBaseEvents @this = (IAvnWindowBaseEvents)ToShadow(thisObject).Callback; + (@this as SharpGen.Runtime.IExceptionCallback)?.RaiseException(__exception__); + return SharpGen.Runtime.Result.GetResultFromException(__exception__).Code; + } + } + + [System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(System.Runtime.InteropServices.CallingConvention.ThisCall)] + private delegate void ClosedDelegate(System.IntPtr thisObject); + private static unsafe void Closed(System.IntPtr thisObject) + { + try + { + IAvnWindowBaseEvents @this = (IAvnWindowBaseEvents)ToShadow(thisObject).Callback; + @this.Closed(); + } + catch (System.Exception __exception__) + { + IAvnWindowBaseEvents @this = (IAvnWindowBaseEvents)ToShadow(thisObject).Callback; + (@this as SharpGen.Runtime.IExceptionCallback)?.RaiseException(__exception__); + } + } + + [System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(System.Runtime.InteropServices.CallingConvention.ThisCall)] + private delegate void ActivatedDelegate(System.IntPtr thisObject); + private static unsafe void Activated(System.IntPtr thisObject) + { + try + { + IAvnWindowBaseEvents @this = (IAvnWindowBaseEvents)ToShadow(thisObject).Callback; + @this.Activated(); + } + catch (System.Exception __exception__) + { + IAvnWindowBaseEvents @this = (IAvnWindowBaseEvents)ToShadow(thisObject).Callback; + (@this as SharpGen.Runtime.IExceptionCallback)?.RaiseException(__exception__); + } + } + + [System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(System.Runtime.InteropServices.CallingConvention.ThisCall)] + private delegate void DeactivatedDelegate(System.IntPtr thisObject); + private static unsafe void Deactivated(System.IntPtr thisObject) + { + try + { + IAvnWindowBaseEvents @this = (IAvnWindowBaseEvents)ToShadow(thisObject).Callback; + @this.Deactivated(); + } + catch (System.Exception __exception__) + { + IAvnWindowBaseEvents @this = (IAvnWindowBaseEvents)ToShadow(thisObject).Callback; + (@this as SharpGen.Runtime.IExceptionCallback)?.RaiseException(__exception__); + } + } + + [System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(System.Runtime.InteropServices.CallingConvention.ThisCall)] + private delegate void ResizedDelegate(System.IntPtr thisObject, void *arg0); + private static unsafe void Resized(System.IntPtr thisObject, void *param0) + { + try + { + Avalonia.Native.Interop.AvnSize size = System.Runtime.CompilerServices.Unsafe.AsRef(param0); + IAvnWindowBaseEvents @this = (IAvnWindowBaseEvents)ToShadow(thisObject).Callback; + @this.Resized(size); + } + catch (System.Exception __exception__) + { + IAvnWindowBaseEvents @this = (IAvnWindowBaseEvents)ToShadow(thisObject).Callback; + (@this as SharpGen.Runtime.IExceptionCallback)?.RaiseException(__exception__); + } + } + + [System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(System.Runtime.InteropServices.CallingConvention.ThisCall)] + private delegate void PositionChangedDelegate(System.IntPtr thisObject, Avalonia.Native.Interop.AvnPoint arg0); + private static unsafe void PositionChanged(System.IntPtr thisObject, Avalonia.Native.Interop.AvnPoint param0) + { + try + { + Avalonia.Native.Interop.AvnPoint position = default (Avalonia.Native.Interop.AvnPoint); + position = (Avalonia.Native.Interop.AvnPoint)param0; + IAvnWindowBaseEvents @this = (IAvnWindowBaseEvents)ToShadow(thisObject).Callback; + @this.PositionChanged(position); + } + catch (System.Exception __exception__) + { + IAvnWindowBaseEvents @this = (IAvnWindowBaseEvents)ToShadow(thisObject).Callback; + (@this as SharpGen.Runtime.IExceptionCallback)?.RaiseException(__exception__); + } + } + + [System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(System.Runtime.InteropServices.CallingConvention.ThisCall)] + private delegate void RawMouseEventDelegate(System.IntPtr thisObject, int arg0, System.UInt32 arg1, int arg2, Avalonia.Native.Interop.AvnPoint arg3, Avalonia.Native.Interop.AvnVector arg4); + private static unsafe void RawMouseEvent(System.IntPtr thisObject, int param0, System.UInt32 param1, int param2, Avalonia.Native.Interop.AvnPoint param3, Avalonia.Native.Interop.AvnVector param4) + { + try + { + Avalonia.Native.Interop.AvnRawMouseEventType type = default (Avalonia.Native.Interop.AvnRawMouseEventType); + type = (Avalonia.Native.Interop.AvnRawMouseEventType)param0; + System.UInt32 timeStamp = default (System.UInt32); + timeStamp = (System.UInt32)param1; + Avalonia.Native.Interop.AvnInputModifiers modifiers = default (Avalonia.Native.Interop.AvnInputModifiers); + modifiers = (Avalonia.Native.Interop.AvnInputModifiers)param2; + Avalonia.Native.Interop.AvnPoint point = default (Avalonia.Native.Interop.AvnPoint); + point = (Avalonia.Native.Interop.AvnPoint)param3; + Avalonia.Native.Interop.AvnVector delta = default (Avalonia.Native.Interop.AvnVector); + delta = (Avalonia.Native.Interop.AvnVector)param4; + IAvnWindowBaseEvents @this = (IAvnWindowBaseEvents)ToShadow(thisObject).Callback; + @this.RawMouseEvent(type, timeStamp, modifiers, point, delta); + } + catch (System.Exception __exception__) + { + IAvnWindowBaseEvents @this = (IAvnWindowBaseEvents)ToShadow(thisObject).Callback; + (@this as SharpGen.Runtime.IExceptionCallback)?.RaiseException(__exception__); + } + } + + [System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(System.Runtime.InteropServices.CallingConvention.ThisCall)] + private delegate System.Byte RawKeyEventDelegate(System.IntPtr thisObject, int arg0, System.UInt32 arg1, int arg2, System.UInt32 arg3); + private static unsafe System.Byte RawKeyEvent(System.IntPtr thisObject, int param0, System.UInt32 param1, int param2, System.UInt32 param3) + { + try + { + System.Boolean __result__ = default (System.Boolean); + System.Byte __result__native; + Avalonia.Native.Interop.AvnRawKeyEventType type = default (Avalonia.Native.Interop.AvnRawKeyEventType); + type = (Avalonia.Native.Interop.AvnRawKeyEventType)param0; + System.UInt32 timeStamp = default (System.UInt32); + timeStamp = (System.UInt32)param1; + Avalonia.Native.Interop.AvnInputModifiers modifiers = default (Avalonia.Native.Interop.AvnInputModifiers); + modifiers = (Avalonia.Native.Interop.AvnInputModifiers)param2; + System.UInt32 key = default (System.UInt32); + key = (System.UInt32)param3; + IAvnWindowBaseEvents @this = (IAvnWindowBaseEvents)ToShadow(thisObject).Callback; + __result__ = @this.RawKeyEvent(type, timeStamp, modifiers, key); + __result__native = (System.Byte)(__result__ ? 1 : 0); + return __result__native; + } + catch (System.Exception __exception__) + { + IAvnWindowBaseEvents @this = (IAvnWindowBaseEvents)ToShadow(thisObject).Callback; + (@this as SharpGen.Runtime.IExceptionCallback)?.RaiseException(__exception__); + return default (System.Byte); + } + } + + [System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(System.Runtime.InteropServices.CallingConvention.ThisCall)] + private delegate System.Byte RawTextInputEventDelegate(System.IntPtr thisObject, System.UInt32 arg0, void *arg1); + private static unsafe System.Byte RawTextInputEvent(System.IntPtr thisObject, System.UInt32 param0, void *param1) + { + try + { + System.Boolean __result__ = default (System.Boolean); + System.Byte __result__native; + System.UInt32 timeStamp = default (System.UInt32); + timeStamp = (System.UInt32)param0; + System.String text = default (System.String); + System.IntPtr text_ = (System.IntPtr)param1; + IAvnWindowBaseEvents @this = (IAvnWindowBaseEvents)ToShadow(thisObject).Callback; + text = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(text_); + __result__ = @this.RawTextInputEvent(timeStamp, text); + __result__native = (System.Byte)(__result__ ? 1 : 0); + return __result__native; + } + catch (System.Exception __exception__) + { + IAvnWindowBaseEvents @this = (IAvnWindowBaseEvents)ToShadow(thisObject).Callback; + (@this as SharpGen.Runtime.IExceptionCallback)?.RaiseException(__exception__); + return default (System.Byte); + } + } + + [System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(System.Runtime.InteropServices.CallingConvention.ThisCall)] + private delegate void ScalingChangedDelegate(System.IntPtr thisObject, double arg0); + private static unsafe void ScalingChanged(System.IntPtr thisObject, double param0) + { + try + { + System.Double scaling = default (System.Double); + scaling = (System.Double)param0; + IAvnWindowBaseEvents @this = (IAvnWindowBaseEvents)ToShadow(thisObject).Callback; + @this.ScalingChanged(scaling); + } + catch (System.Exception __exception__) + { + IAvnWindowBaseEvents @this = (IAvnWindowBaseEvents)ToShadow(thisObject).Callback; + (@this as SharpGen.Runtime.IExceptionCallback)?.RaiseException(__exception__); + } + } + + [System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(System.Runtime.InteropServices.CallingConvention.ThisCall)] + private delegate void RunRenderPriorityJobsDelegate(System.IntPtr thisObject); + private static unsafe void RunRenderPriorityJobs(System.IntPtr thisObject) + { + try + { + IAvnWindowBaseEvents @this = (IAvnWindowBaseEvents)ToShadow(thisObject).Callback; + @this.RunRenderPriorityJobs(); + } + catch (System.Exception __exception__) + { + IAvnWindowBaseEvents @this = (IAvnWindowBaseEvents)ToShadow(thisObject).Callback; + (@this as SharpGen.Runtime.IExceptionCallback)?.RaiseException(__exception__); + } + } + + [System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(System.Runtime.InteropServices.CallingConvention.ThisCall)] + private delegate void LostFocusDelegate(System.IntPtr thisObject); + private static unsafe void LostFocus(System.IntPtr thisObject) + { + try + { + IAvnWindowBaseEvents @this = (IAvnWindowBaseEvents)ToShadow(thisObject).Callback; + @this.LostFocus(); + } + catch (System.Exception __exception__) + { + IAvnWindowBaseEvents @this = (IAvnWindowBaseEvents)ToShadow(thisObject).Callback; + (@this as SharpGen.Runtime.IExceptionCallback)?.RaiseException(__exception__); + } + } + + [System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(System.Runtime.InteropServices.CallingConvention.ThisCall)] + private delegate Avalonia.Native.Interop.AvnDragDropEffects DragEventDelegate(System.IntPtr thisObject, int arg0, Avalonia.Native.Interop.AvnPoint arg1, int arg2, int arg3, void *arg4, void *arg5); + private static unsafe Avalonia.Native.Interop.AvnDragDropEffects DragEvent(System.IntPtr thisObject, int param0, Avalonia.Native.Interop.AvnPoint param1, int param2, int param3, void *param4, void *param5) + { + try + { + Avalonia.Native.Interop.AvnDragDropEffects __result__ = default (Avalonia.Native.Interop.AvnDragDropEffects); + Avalonia.Native.Interop.AvnDragEventType type = default (Avalonia.Native.Interop.AvnDragEventType); + type = (Avalonia.Native.Interop.AvnDragEventType)param0; + Avalonia.Native.Interop.AvnPoint position = default (Avalonia.Native.Interop.AvnPoint); + position = (Avalonia.Native.Interop.AvnPoint)param1; + Avalonia.Native.Interop.AvnInputModifiers modifiers = default (Avalonia.Native.Interop.AvnInputModifiers); + modifiers = (Avalonia.Native.Interop.AvnInputModifiers)param2; + Avalonia.Native.Interop.AvnDragDropEffects effects = default (Avalonia.Native.Interop.AvnDragDropEffects); + effects = (Avalonia.Native.Interop.AvnDragDropEffects)param3; + Avalonia.Native.Interop.IAvnClipboard clipboard = default (Avalonia.Native.Interop.IAvnClipboard); + System.IntPtr clipboard_ = (System.IntPtr)param4; + System.IntPtr dataObjectHandle = default (System.IntPtr); + dataObjectHandle = (System.IntPtr)param5; + IAvnWindowBaseEvents @this = (IAvnWindowBaseEvents)ToShadow(thisObject).Callback; + if (clipboard_ != System.IntPtr.Zero) + clipboard = new Avalonia.Native.Interop.IAvnClipboard(clipboard_); + else + clipboard = null; + __result__ = @this.DragEvent(type, position, modifiers, effects, clipboard, dataObjectHandle); + return __result__; + } + catch (System.Exception __exception__) + { + IAvnWindowBaseEvents @this = (IAvnWindowBaseEvents)ToShadow(thisObject).Callback; + (@this as SharpGen.Runtime.IExceptionCallback)?.RaiseException(__exception__); + return default (Avalonia.Native.Interop.AvnDragDropEffects); + } + } + } + + protected override SharpGen.Runtime.CppObjectVtbl Vtbl + { + get; + } + + = new Avalonia.Native.Interop.IAvnWindowBaseEventsShadow.IAvnWindowBaseEventsVtbl(0); + } + + [System.Runtime.InteropServices.GuidAttribute("2e2cda0a-9ae5-4f1b-8e20-081a04279f05"), SharpGen.Runtime.ShadowAttribute(typeof (Avalonia.Native.Interop.IAvnWindowBaseEventsShadow))] + public partial interface IAvnWindowBaseEvents : SharpGen.Runtime.IUnknown + { + void Paint(); + void Closed(); + void Activated(); + void Deactivated(); + void Resized(Avalonia.Native.Interop.AvnSize size); + void PositionChanged(Avalonia.Native.Interop.AvnPoint position); + void RawMouseEvent(Avalonia.Native.Interop.AvnRawMouseEventType type, System.UInt32 timeStamp, Avalonia.Native.Interop.AvnInputModifiers modifiers, Avalonia.Native.Interop.AvnPoint point, Avalonia.Native.Interop.AvnVector delta); + System.Boolean RawKeyEvent(Avalonia.Native.Interop.AvnRawKeyEventType type, System.UInt32 timeStamp, Avalonia.Native.Interop.AvnInputModifiers modifiers, System.UInt32 key); + System.Boolean RawTextInputEvent(System.UInt32 timeStamp, System.String text); + void ScalingChanged(System.Double scaling); + void RunRenderPriorityJobs(); + void LostFocus(); + Avalonia.Native.Interop.AvnDragDropEffects DragEvent(Avalonia.Native.Interop.AvnDragEventType type, Avalonia.Native.Interop.AvnPoint position, Avalonia.Native.Interop.AvnInputModifiers modifiers, Avalonia.Native.Interop.AvnDragDropEffects effects, Avalonia.Native.Interop.IAvnClipboard clipboard, System.IntPtr dataObjectHandle); + } + + class IAvnWindowEventsShadow : Avalonia.Native.Interop.IAvnWindowBaseEventsShadow + { + protected unsafe class IAvnWindowEventsVtbl : Avalonia.Native.Interop.IAvnWindowBaseEventsShadow.IAvnWindowBaseEventsVtbl + { + public IAvnWindowEventsVtbl(int numberOfCallbackMethods): base (numberOfCallbackMethods + 3) + { + AddMethod(new ClosingDelegate(Closing)); + AddMethod(new WindowStateChangedDelegate(WindowStateChanged)); + AddMethod(new GotInputWhenDisabledDelegate(GotInputWhenDisabled)); + } + + [System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(System.Runtime.InteropServices.CallingConvention.ThisCall)] + private delegate System.Byte ClosingDelegate(System.IntPtr thisObject); + private static unsafe System.Byte Closing(System.IntPtr thisObject) + { + try + { + System.Boolean __result__ = default (System.Boolean); + System.Byte __result__native; + IAvnWindowEvents @this = (IAvnWindowEvents)ToShadow(thisObject).Callback; + __result__ = @this.Closing(); + __result__native = (System.Byte)(__result__ ? 1 : 0); + return __result__native; + } + catch (System.Exception __exception__) + { + IAvnWindowEvents @this = (IAvnWindowEvents)ToShadow(thisObject).Callback; + (@this as SharpGen.Runtime.IExceptionCallback)?.RaiseException(__exception__); + return default (System.Byte); + } + } + + [System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(System.Runtime.InteropServices.CallingConvention.ThisCall)] + private delegate void WindowStateChangedDelegate(System.IntPtr thisObject, int arg0); + private static unsafe void WindowStateChanged(System.IntPtr thisObject, int param0) + { + try + { + Avalonia.Native.Interop.AvnWindowState state = default (Avalonia.Native.Interop.AvnWindowState); + state = (Avalonia.Native.Interop.AvnWindowState)param0; + IAvnWindowEvents @this = (IAvnWindowEvents)ToShadow(thisObject).Callback; + @this.WindowStateChanged(state); + } + catch (System.Exception __exception__) + { + IAvnWindowEvents @this = (IAvnWindowEvents)ToShadow(thisObject).Callback; + (@this as SharpGen.Runtime.IExceptionCallback)?.RaiseException(__exception__); + } + } + + [System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(System.Runtime.InteropServices.CallingConvention.ThisCall)] + private delegate void GotInputWhenDisabledDelegate(System.IntPtr thisObject); + private static unsafe void GotInputWhenDisabled(System.IntPtr thisObject) + { + try + { + IAvnWindowEvents @this = (IAvnWindowEvents)ToShadow(thisObject).Callback; + @this.GotInputWhenDisabled(); + } + catch (System.Exception __exception__) + { + IAvnWindowEvents @this = (IAvnWindowEvents)ToShadow(thisObject).Callback; + (@this as SharpGen.Runtime.IExceptionCallback)?.RaiseException(__exception__); + } + } + } + + protected override SharpGen.Runtime.CppObjectVtbl Vtbl + { + get; + } + + = new Avalonia.Native.Interop.IAvnWindowEventsShadow.IAvnWindowEventsVtbl(0); + } + + [System.Runtime.InteropServices.GuidAttribute("2e2cda0a-9ae5-4f1b-8e20-081a04279f06"), SharpGen.Runtime.ShadowAttribute(typeof (Avalonia.Native.Interop.IAvnWindowEventsShadow))] + public partial interface IAvnWindowEvents : Avalonia.Native.Interop.IAvnWindowBaseEvents + { + System.Boolean Closing(); + void WindowStateChanged(Avalonia.Native.Interop.AvnWindowState state); + void GotInputWhenDisabled(); + } +} \ No newline at end of file diff --git a/src/Avalonia.Native/Generated/LocalInterop.cs b/src/Avalonia.Native/Generated/LocalInterop.cs new file mode 100644 index 0000000000..41e69a6bdc --- /dev/null +++ b/src/Avalonia.Native/Generated/LocalInterop.cs @@ -0,0 +1,202 @@ +// + +namespace Avalonia.Native +{ + internal static partial class LocalInterop + { + public static unsafe int CalliThisCallint(void *thisObject, void *methodPtr) + { + throw null; + } + + public static unsafe void CalliThisCallvoid(void *thisObject, void *methodPtr) + { + throw null; + } + + public static unsafe void CalliThisCallvoid(void *thisObject, void *param0, void *methodPtr) + { + throw null; + } + + public static unsafe void CalliThisCallvoid0(void *thisObject, Avalonia.Native.Interop.AvnPoint param0, void *methodPtr) + { + throw null; + } + + public static unsafe void CalliThisCallvoid0(void *thisObject, int param0, System.UInt32 param1, int param2, Avalonia.Native.Interop.AvnPoint param3, Avalonia.Native.Interop.AvnVector param4, void *methodPtr) + { + throw null; + } + + public static unsafe System.Byte CalliThisCallSystemByte(void *thisObject, int param0, System.UInt32 param1, int param2, System.UInt32 param3, void *methodPtr) + { + throw null; + } + + public static unsafe System.Byte CalliThisCallSystemByte(void *thisObject, System.UInt32 param0, void *param1, void *methodPtr) + { + throw null; + } + + public static unsafe void CalliThisCallvoid(void *thisObject, double param0, void *methodPtr) + { + throw null; + } + + public static unsafe Avalonia.Native.Interop.AvnDragDropEffects CalliThisCallAvaloniaNativeInteropAvnDragDropEffects0(void *thisObject, int param0, Avalonia.Native.Interop.AvnPoint param1, int param2, int param3, void *param4, void *param5, void *methodPtr) + { + throw null; + } + + public static unsafe System.Byte CalliThisCallSystemByte(void *thisObject, void *methodPtr) + { + throw null; + } + + public static unsafe void CalliThisCallvoid(void *thisObject, int param0, void *methodPtr) + { + throw null; + } + + public static unsafe int CalliThisCallint(void *thisObject, void *param0, void *methodPtr) + { + throw null; + } + + public static unsafe int CalliThisCallint0(void *thisObject, Avalonia.Native.Interop.AvnSize param0, Avalonia.Native.Interop.AvnSize param1, void *methodPtr) + { + throw null; + } + + public static unsafe int CalliThisCallint(void *thisObject, double param0, double param1, void *methodPtr) + { + throw null; + } + + public static unsafe int CalliThisCallint0(void *thisObject, Avalonia.Native.Interop.AvnRect param0, void *methodPtr) + { + throw null; + } + + public static unsafe int CalliThisCallint(void *thisObject, int param0, void *methodPtr) + { + throw null; + } + + public static unsafe int CalliThisCallint0(void *thisObject, Avalonia.Native.Interop.AvnPoint param0, void *methodPtr) + { + throw null; + } + + public static unsafe int CalliThisCallint0(void *thisObject, Avalonia.Native.Interop.AvnPoint param0, void *param1, void *methodPtr) + { + throw null; + } + + public static unsafe int CalliThisCallint(void *thisObject, void *param0, void *param1, void *methodPtr) + { + throw null; + } + + public static unsafe int CalliThisCallint(void *thisObject, System.Byte param0, void *methodPtr) + { + throw null; + } + + public static unsafe int CalliThisCallint0(void *thisObject, int param0, Avalonia.Native.Interop.AvnPoint param1, void *param2, void *param3, void *param4, void *methodPtr) + { + throw null; + } + + public static unsafe int CalliThisCallint0(void *thisObject, Avalonia.Native.Interop.AvnColor param0, void *methodPtr) + { + throw null; + } + + public static unsafe int CalliThisCallint(void *thisObject, double param0, void *methodPtr) + { + throw null; + } + + public static unsafe System.IntPtr CalliThisCallSystemIntPtr(void *thisObject, void *methodPtr) + { + throw null; + } + + public static unsafe System.IntPtr CalliThisCallSystemIntPtr(void *thisObject, int param0, int param1, void *param2, void *methodPtr) + { + throw null; + } + + public static unsafe void CalliThisCallvoid(void *thisObject, int param0, void *param1, void *methodPtr) + { + throw null; + } + + public static unsafe void CalliThisCallvoid(void *thisObject, void *param0, void *param1, void *param2, void *param3, void *methodPtr) + { + throw null; + } + + public static unsafe void CalliThisCallvoid(void *thisObject, void *param0, void *param1, System.Byte param2, void *param3, void *param4, void *param5, void *param6, void *methodPtr) + { + throw null; + } + + public static unsafe void CalliThisCallvoid(void *thisObject, void *param0, void *param1, void *param2, void *param3, void *param4, void *param5, void *methodPtr) + { + throw null; + } + + public static unsafe int CalliThisCallint(void *thisObject, int param0, void *param1, void *methodPtr) + { + throw null; + } + + public static unsafe int CalliThisCallint(void *thisObject, void *param0, void *param1, int param2, void *methodPtr) + { + throw null; + } + + public static unsafe System.IntPtr CalliThisCallSystemIntPtr(void *thisObject, void *param0, void *methodPtr) + { + throw null; + } + + public static unsafe int CalliThisCallint(void *thisObject, void *param0, int param1, void *methodPtr) + { + throw null; + } + + public static unsafe System.UInt32 CalliThisCallSystemUInt32(void *thisObject, void *methodPtr) + { + throw null; + } + + public static unsafe int CalliThisCallint(void *thisObject, System.UInt32 param0, void *param1, void *methodPtr) + { + throw null; + } + + public static unsafe void CalliThisCallvoid(void *thisObject, float param0, float param1, float param2, float param3, void *methodPtr) + { + throw null; + } + + public static unsafe void CalliThisCallvoid(void *thisObject, float param0, float param1, void *methodPtr) + { + throw null; + } + + public static unsafe int CalliThisCallint(void *thisObject, void *param0, void *param1, void *param2, void *methodPtr) + { + throw null; + } + + public static unsafe void CalliThisCallvoid(void *thisObject, int param0, System.Byte param1, void *methodPtr) + { + throw null; + } + } +} \ No newline at end of file diff --git a/src/Avalonia.Native/Generated/Structures.cs b/src/Avalonia.Native/Generated/Structures.cs new file mode 100644 index 0000000000..fc871a2516 --- /dev/null +++ b/src/Avalonia.Native/Generated/Structures.cs @@ -0,0 +1,246 @@ +// + +namespace Avalonia.Native.Interop +{ + /// + /// No documentation. + /// + /// AvnColor + /// AvnColor + [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 0, CharSet = System.Runtime.InteropServices.CharSet.Unicode)] + public partial struct AvnColor + { + /// + /// No documentation. + /// + /// Alpha + /// Alpha + public System.Byte Alpha; + /// + /// No documentation. + /// + /// Red + /// Red + public System.Byte Red; + /// + /// No documentation. + /// + /// Green + /// Green + public System.Byte Green; + /// + /// No documentation. + /// + /// Blue + /// Blue + public System.Byte Blue; + } + + /// + /// No documentation. + /// + /// AvnFramebuffer + /// AvnFramebuffer + [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 0, CharSet = System.Runtime.InteropServices.CharSet.Unicode)] + public partial struct AvnFramebuffer + { + /// + /// No documentation. + /// + /// Data + /// Data + public System.IntPtr Data; + /// + /// No documentation. + /// + /// Width + /// Width + public System.Int32 Width; + /// + /// No documentation. + /// + /// Height + /// Height + public System.Int32 Height; + /// + /// No documentation. + /// + /// Stride + /// Stride + public System.Int32 Stride; + /// + /// No documentation. + /// + /// Dpi + /// Dpi + public Avalonia.Native.Interop.AvnVector Dpi; + /// + /// No documentation. + /// + /// PixelFormat + /// PixelFormat + public Avalonia.Native.Interop.AvnPixelFormat PixelFormat; + } + + /// + /// No documentation. + /// + /// AvnPixelSize + /// AvnPixelSize + [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 0, CharSet = System.Runtime.InteropServices.CharSet.Unicode)] + public partial struct AvnPixelSize + { + /// + /// No documentation. + /// + /// Width + /// Width + public System.Int32 Width; + /// + /// No documentation. + /// + /// Height + /// Height + public System.Int32 Height; + } + + /// + /// No documentation. + /// + /// AvnPoint + /// AvnPoint + [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 0, CharSet = System.Runtime.InteropServices.CharSet.Unicode)] + public partial struct AvnPoint + { + /// + /// No documentation. + /// + /// X + /// X + public System.Double X; + /// + /// No documentation. + /// + /// Y + /// Y + public System.Double Y; + } + + /// + /// No documentation. + /// + /// AvnRect + /// AvnRect + [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 0, CharSet = System.Runtime.InteropServices.CharSet.Unicode)] + public partial struct AvnRect + { + /// + /// No documentation. + /// + /// X + /// X + public System.Double X; + /// + /// No documentation. + /// + /// Y + /// Y + public System.Double Y; + /// + /// No documentation. + /// + /// Width + /// Width + public System.Double Width; + /// + /// No documentation. + /// + /// Height + /// Height + public System.Double Height; + } + + /// + /// No documentation. + /// + /// AvnScreen + /// AvnScreen + [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 0, CharSet = System.Runtime.InteropServices.CharSet.Unicode)] + public partial struct AvnScreen + { + /// + /// No documentation. + /// + /// Bounds + /// Bounds + public Avalonia.Native.Interop.AvnRect Bounds; + /// + /// No documentation. + /// + /// WorkingArea + /// WorkingArea + public Avalonia.Native.Interop.AvnRect WorkingArea; + /// + /// No documentation. + /// + /// PixelDensity + /// PixelDensity + public System.Single PixelDensity; + /// + /// No documentation. + /// + /// Primary + /// Primary + public bool Primary + { + get => 0 != _Primary; + set => _Primary = (System.Byte)(value ? 1 : 0); + } + + internal System.Byte _Primary; + } + + /// + /// No documentation. + /// + /// AvnSize + /// AvnSize + [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 0, CharSet = System.Runtime.InteropServices.CharSet.Unicode)] + public partial struct AvnSize + { + /// + /// No documentation. + /// + /// Width + /// Width + public System.Double Width; + /// + /// No documentation. + /// + /// Height + /// Height + public System.Double Height; + } + + /// + /// No documentation. + /// + /// AvnVector + /// AvnVector + [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 0, CharSet = System.Runtime.InteropServices.CharSet.Unicode)] + public partial struct AvnVector + { + /// + /// No documentation. + /// + /// X + /// X + public System.Double X; + /// + /// No documentation. + /// + /// Y + /// Y + public System.Double Y; + } +} \ No newline at end of file From df19b1c1274a3c7cf3160a29e55cdaba5fde5a65 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 16 Aug 2020 22:07:50 +0100 Subject: [PATCH 217/344] change api stability to preview3. --- build/ApiDiff.props | 2 +- src/Avalonia.Base/ApiCompatBaseline.txt | 6 ------ src/Avalonia.Controls/ApiCompatBaseline.txt | 7 ------- src/Avalonia.Visuals/ApiCompatBaseline.txt | 14 -------------- 4 files changed, 1 insertion(+), 28 deletions(-) delete mode 100644 src/Avalonia.Base/ApiCompatBaseline.txt delete mode 100644 src/Avalonia.Controls/ApiCompatBaseline.txt delete mode 100644 src/Avalonia.Visuals/ApiCompatBaseline.txt diff --git a/build/ApiDiff.props b/build/ApiDiff.props index 1573dc2dd6..da82fbcc51 100644 --- a/build/ApiDiff.props +++ b/build/ApiDiff.props @@ -1,6 +1,6 @@  - 0.10.0-preview2 + 0.10.0-preview3 $(PackageId) Avalonia diff --git a/src/Avalonia.Base/ApiCompatBaseline.txt b/src/Avalonia.Base/ApiCompatBaseline.txt deleted file mode 100644 index b0b7371cd7..0000000000 --- a/src/Avalonia.Base/ApiCompatBaseline.txt +++ /dev/null @@ -1,6 +0,0 @@ -Compat issues with assembly Avalonia.Base: -MembersMustExist : Member 'public void Avalonia.DirectProperty..ctor(System.String, System.Func, System.Action, Avalonia.DirectPropertyMetadata, System.Boolean)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'protected void Avalonia.DirectPropertyBase..ctor(Avalonia.AvaloniaProperty, System.Type, Avalonia.PropertyMetadata, System.Boolean)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'protected void Avalonia.DirectPropertyBase..ctor(System.String, System.Type, Avalonia.PropertyMetadata, System.Boolean)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public System.Boolean Avalonia.DirectPropertyBase.IsDataValidationEnabled.get()' does not exist in the implementation but it does exist in the contract. -Total Issues: 4 diff --git a/src/Avalonia.Controls/ApiCompatBaseline.txt b/src/Avalonia.Controls/ApiCompatBaseline.txt deleted file mode 100644 index 0a2415a263..0000000000 --- a/src/Avalonia.Controls/ApiCompatBaseline.txt +++ /dev/null @@ -1,7 +0,0 @@ -Compat issues with assembly Avalonia.Controls: -MembersMustExist : Member 'protected void Avalonia.Controls.ComboBox.PopupClosedOverride(Avalonia.Controls.Primitives.PopupClosedEventArgs)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public Avalonia.StyledProperty Avalonia.StyledProperty Avalonia.Controls.Primitives.Popup.StaysOpenProperty' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public void Avalonia.Controls.Primitives.Popup.add_Closed(System.EventHandler)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public void Avalonia.Controls.Primitives.Popup.remove_Closed(System.EventHandler)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'Avalonia.Controls.Primitives.PopupClosedEventArgs' does not exist in the implementation but it does exist in the contract. -Total Issues: 5 diff --git a/src/Avalonia.Visuals/ApiCompatBaseline.txt b/src/Avalonia.Visuals/ApiCompatBaseline.txt deleted file mode 100644 index 849e957a72..0000000000 --- a/src/Avalonia.Visuals/ApiCompatBaseline.txt +++ /dev/null @@ -1,14 +0,0 @@ -Compat issues with assembly Avalonia.Visuals: -EnumValuesMustMatch : Enum value 'Avalonia.Media.FontStyle Avalonia.Media.FontStyle.Italic' is (System.Int32)1 in the implementation but (System.Int32)2 in the contract. -EnumValuesMustMatch : Enum value 'Avalonia.Media.FontStyle Avalonia.Media.FontStyle.Oblique' is (System.Int32)2 in the implementation but (System.Int32)1 in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.AlphaFormat Avalonia.Platform.IPlatformRenderInterface.DefaultAlphaFormat' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.PixelFormat Avalonia.Platform.IPlatformRenderInterface.DefaultPixelFormat' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.IWriteableBitmapImpl Avalonia.Platform.IPlatformRenderInterface.CreateWriteableBitmap(Avalonia.PixelSize, Avalonia.Vector, Avalonia.Platform.PixelFormat, Avalonia.Platform.AlphaFormat)' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.IWriteableBitmapImpl Avalonia.Platform.IPlatformRenderInterface.CreateWriteableBitmap(Avalonia.PixelSize, Avalonia.Vector, System.Nullable)' is present in the contract but not in the implementation. -MembersMustExist : Member 'public Avalonia.Platform.IWriteableBitmapImpl Avalonia.Platform.IPlatformRenderInterface.CreateWriteableBitmap(Avalonia.PixelSize, Avalonia.Vector, System.Nullable)' does not exist in the implementation but it does exist in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.AlphaFormat Avalonia.Platform.IPlatformRenderInterface.DefaultAlphaFormat.get()' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.PixelFormat Avalonia.Platform.IPlatformRenderInterface.DefaultPixelFormat.get()' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.IBitmapImpl Avalonia.Platform.IPlatformRenderInterface.LoadBitmap(Avalonia.Platform.PixelFormat, Avalonia.Platform.AlphaFormat, System.IntPtr, Avalonia.PixelSize, Avalonia.Vector, System.Int32)' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.IBitmapImpl Avalonia.Platform.IPlatformRenderInterface.LoadBitmap(Avalonia.Platform.PixelFormat, System.IntPtr, Avalonia.PixelSize, Avalonia.Vector, System.Int32)' is present in the contract but not in the implementation. -MembersMustExist : Member 'public Avalonia.Platform.IBitmapImpl Avalonia.Platform.IPlatformRenderInterface.LoadBitmap(Avalonia.Platform.PixelFormat, System.IntPtr, Avalonia.PixelSize, Avalonia.Vector, System.Int32)' does not exist in the implementation but it does exist in the contract. -Total Issues: 12 From 1828acc05c139fc6e5a097a8f245eb85501fcbdc Mon Sep 17 00:00:00 2001 From: Arthur Date: Mon, 17 Aug 2020 01:33:59 +0300 Subject: [PATCH 218/344] Changing http links to https --- readme.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/readme.md b/readme.md index c1bf5bbfde..ccdbbfb967 100644 --- a/readme.md +++ b/readme.md @@ -16,7 +16,7 @@ To see the status of some of our features, please see our [Roadmap](https://gith ## 🚀 Getting Started -The Avalonia [Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaforVisualStudio) contains project and control templates that will help you get started, or you can use the .NET Core CLI. For a starter guide see our [documentation](http://avaloniaui.net/docs/quickstart/create-new-project). +The Avalonia [Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaforVisualStudio) contains project and control templates that will help you get started, or you can use the .NET Core CLI. For a starter guide see our [documentation](https://avaloniaui.net/docs/quickstart/create-new-project). Avalonia is delivered via NuGet package manager. You can find the packages here: https://www.nuget.org/packages/Avalonia/ @@ -47,7 +47,7 @@ We also have a [nightly build](https://github.com/AvaloniaUI/Avalonia/wiki/Using ## Documentation -Documentation can be found on our website at http://avaloniaui.net/docs/. We also have a [tutorial](http://avaloniaui.net/docs/tutorial/) over there for newcomers. +Documentation can be found on our website at https://avaloniaui.net/docs/. We also have a [tutorial](https://avaloniaui.net/docs/tutorial/) over there for newcomers. ## Building and Using @@ -68,7 +68,7 @@ Avalonia is licenced under the [MIT licence](licence.md). ## Contributors -This project exists thanks to all the people who contribute. [[Contribute](http://avaloniaui.net/contributing)]. +This project exists thanks to all the people who contribute. [[Contribute](https://avaloniaui.net/contributing)]. ### Backers From c8d26de9489387f82ce66313db3651a093762c85 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Mon, 17 Aug 2020 16:05:20 +0100 Subject: [PATCH 219/344] Add failing unit test. --- .../TextBoxTests.cs | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs index af3b68f4a0..7a409d494c 100644 --- a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs @@ -17,6 +17,46 @@ namespace Avalonia.Controls.UnitTests { public class TextBoxTests { + [Fact] + public void Opening_Context_Menu_Does_not_Loose_Selection() + { + using (UnitTestApplication.Start(FocusServices)) + { + var target1 = new TextBox + { + Template = CreateTemplate(), + Text = "1234", + ContextMenu = new TestContextMenu() + }; + + 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 }; + + target1.SelectionStart = 0; + target1.SelectionEnd = 3; + + target1.Focus(); + Assert.False(target2.IsFocused); + Assert.True(target1.IsFocused); + + target2.Focus(); + + Assert.Equal("123", target1.SelectedText); + } + } + [Fact] public void DefaultBindingMode_Should_Be_TwoWay() { @@ -694,5 +734,13 @@ namespace Avalonia.Controls.UnitTests public Task GetDataAsync(string format) => Task.FromResult((object)null); } + + private class TestContextMenu : ContextMenu + { + public TestContextMenu() + { + IsOpen = true; + } + } } } From 54cedcea877ea7f8026df77cc09070e11ba1734c Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Mon, 17 Aug 2020 16:06:07 +0100 Subject: [PATCH 220/344] dont allow text selection to be lost when context menu is opened... i.e. for copy and paste to work. --- src/Avalonia.Controls/ContextMenu.cs | 3 +-- src/Avalonia.Controls/TextBox.cs | 11 ++++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Avalonia.Controls/ContextMenu.cs b/src/Avalonia.Controls/ContextMenu.cs index b4e4dd5071..9bb4cc4816 100644 --- a/src/Avalonia.Controls/ContextMenu.cs +++ b/src/Avalonia.Controls/ContextMenu.cs @@ -280,9 +280,8 @@ namespace Avalonia.Controls } _popup.Child = this; - _popup.IsOpen = true; - IsOpen = true; + _popup.IsOpen = true; RaiseEvent(new RoutedEventArgs { diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index 7e28d88581..4e742b3b7b 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -410,10 +410,15 @@ namespace Avalonia.Controls protected override void OnLostFocus(RoutedEventArgs e) { base.OnLostFocus(e); - SelectionStart = 0; - SelectionEnd = 0; + + if (ContextMenu == null || !ContextMenu.IsOpen) + { + SelectionStart = 0; + SelectionEnd = 0; + RevealPassword = false; + } + _presenter?.HideCaret(); - RevealPassword = false; } protected override void OnTextInput(TextInputEventArgs e) From 89bf711602f59b871dceafcce51bdff837f7fa37 Mon Sep 17 00:00:00 2001 From: danwalmsley Date: Mon, 17 Aug 2020 16:59:33 +0100 Subject: [PATCH 221/344] Lose not Loose! Co-authored-by: Steven Kirk --- tests/Avalonia.Controls.UnitTests/TextBoxTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs index 7a409d494c..f41938a9bb 100644 --- a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs @@ -18,7 +18,7 @@ namespace Avalonia.Controls.UnitTests public class TextBoxTests { [Fact] - public void Opening_Context_Menu_Does_not_Loose_Selection() + public void Opening_Context_Menu_Does_not_Lose_Selection() { using (UnitTestApplication.Start(FocusServices)) { From 9ff731ab701cc61d5e750ac2ed922b9c70c7ff8c Mon Sep 17 00:00:00 2001 From: Maksym Katsydan Date: Mon, 17 Aug 2020 19:39:55 -0400 Subject: [PATCH 222/344] Fix another missing resources on default theme (including #4376) --- src/Avalonia.Controls.DataGrid/Themes/Default.xaml | 10 +++++----- src/Avalonia.Themes.Default/SplitView.xaml | 2 +- src/Avalonia.Themes.Default/TimePicker.xaml | 2 +- src/Avalonia.Themes.Default/ToggleSwitch.xaml | 14 +++++++------- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Avalonia.Controls.DataGrid/Themes/Default.xaml b/src/Avalonia.Controls.DataGrid/Themes/Default.xaml index 738732f671..1d4d88825f 100644 --- a/src/Avalonia.Controls.DataGrid/Themes/Default.xaml +++ b/src/Avalonia.Controls.DataGrid/Themes/Default.xaml @@ -28,7 +28,7 @@ - + @@ -188,7 +188,7 @@ + TextBox A control into which the user can input text - + - + - + - + - - - + + + - - resm fonts - - - - - - - - res fonts - - - - - + + resm fonts + + + + + + + + res fonts + + + + + diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index 86f66fa90d..7798c71377 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -1,3 +1,4 @@ +using System.Windows.Input; using Avalonia.Input.Platform; using System; using System.Collections.Generic; @@ -103,6 +104,21 @@ namespace Avalonia.Controls public static readonly StyledProperty RevealPasswordProperty = AvaloniaProperty.Register(nameof(RevealPassword)); + + public static readonly DirectProperty CanCutProperty = + AvaloniaProperty.RegisterDirect( + nameof(CanCut), + o => o.CanCut); + + public static readonly DirectProperty CanCopyProperty = + AvaloniaProperty.RegisterDirect( + nameof(CanCopy), + o => o.CanCopy); + + public static readonly DirectProperty CanPasteProperty = + AvaloniaProperty.RegisterDirect( + nameof(CanPaste), + o => o.CanPaste); struct UndoRedoState : IEquatable { @@ -126,6 +142,9 @@ namespace Avalonia.Controls private UndoRedoHelper _undoRedoHelper; private bool _isUndoingRedoing; private bool _ignoreTextChanges; + private bool _canCut; + private bool _canCopy; + private bool _canPaste; private string _newLine = Environment.NewLine; private static readonly string[] invalidCharacters = new String[1] { "\u007f" }; @@ -370,6 +389,33 @@ namespace Avalonia.Controls set { SetAndRaise(NewLineProperty, ref _newLine, value); } } + /// + /// Property for determining if the Cut command can be executed. + /// + public bool CanCut + { + get { return _canCut; } + private set { SetAndRaise(CanCutProperty, ref _canCut, value); } + } + + /// + /// Property for determining if the Copy command can be executed. + /// + public bool CanCopy + { + get { return _canCopy; } + private set { SetAndRaise(CanCopyProperty, ref _canCopy, value); } + } + + /// + /// Property for determining if the Paste command can be executed. + /// + public bool CanPaste + { + get { return _canPaste; } + private set { SetAndRaise(CanPasteProperty, ref _canPaste, value); } + } + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { _presenter = e.NameScope.Get("PART_TextPresenter"); @@ -387,9 +433,19 @@ namespace Avalonia.Controls if (change.Property == TextProperty) { UpdatePseudoclasses(); + UpdateCommandStates(); } } + private void UpdateCommandStates() + { + var text = GetSelection(); + var b1 = string.IsNullOrEmpty(text); + CanCopy = !b1; + CanCut = !b1; + CanPaste = !IsReadOnly; + } + protected override void OnGotFocus(GotFocusEventArgs e) { base.OnGotFocus(e); @@ -404,6 +460,8 @@ namespace Avalonia.Controls SelectAll(); } + UpdateCommandStates(); + _presenter?.ShowCaret(); } @@ -418,6 +476,8 @@ namespace Avalonia.Controls RevealPassword = false; } + UpdateCommandStates(); + _presenter?.HideCaret(); } @@ -462,6 +522,9 @@ namespace Avalonia.Controls public async void Cut() { + var text = GetSelection(); + if (text is null) return; + _undoRedoHelper.Snapshot(); Copy(); DeleteSelection(); @@ -470,17 +533,18 @@ namespace Avalonia.Controls public async void Copy() { + var text = GetSelection(); + if (text is null) return; + await ((IClipboard)AvaloniaLocator.Current.GetService(typeof(IClipboard))) - .SetTextAsync(GetSelection()); + .SetTextAsync(text); } public async void Paste() { var text = await ((IClipboard)AvaloniaLocator.Current.GetService(typeof(IClipboard))).GetTextAsync(); - if (text == null) - { - return; - } + + if (text is null) return; _undoRedoHelper.Snapshot(); HandleTextInput(text); From e93ac83ae43b9a2b88311cc11c8e2aa793b3eab5 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 18 Aug 2020 15:14:56 +0100 Subject: [PATCH 227/344] add gesture text. --- samples/ControlCatalog/Pages/TextBoxPage.xaml | 6 +++--- src/Avalonia.Controls/TextBox.cs | 9 +++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/samples/ControlCatalog/Pages/TextBoxPage.xaml b/samples/ControlCatalog/Pages/TextBoxPage.xaml index 88094c70f3..5317e46e81 100644 --- a/samples/ControlCatalog/Pages/TextBoxPage.xaml +++ b/samples/ControlCatalog/Pages/TextBoxPage.xaml @@ -3,9 +3,9 @@ - - - + + + diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index 7798c71377..3b81b5b020 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -19,6 +19,15 @@ namespace Avalonia.Controls { public class TextBox : TemplatedControl, UndoRedoHelper.IUndoRedoHost { + public static KeyGesture CutGesture { get; } = + AvaloniaLocator.Current.GetService()?.Cut.FirstOrDefault(); + + public static KeyGesture CopyGesture { get; } = AvaloniaLocator.Current + .GetService()?.Copy.FirstOrDefault(); + + public static KeyGesture PasteGesture { get; } = AvaloniaLocator.Current + .GetService()?.Paste.FirstOrDefault(); + public static readonly StyledProperty AcceptsReturnProperty = AvaloniaProperty.Register(nameof(AcceptsReturn)); From 5ea8c57f760e755edd03d12f06c13bfda5f2f1f1 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 18 Aug 2020 15:15:22 +0100 Subject: [PATCH 228/344] move standard textbox context menu to the templates. --- samples/ControlCatalog/Pages/TextBoxPage.xaml | 12 ------------ src/Avalonia.Themes.Default/TextBox.xaml | 8 ++++++++ src/Avalonia.Themes.Fluent/TextBox.xaml | 7 +++++++ 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/samples/ControlCatalog/Pages/TextBoxPage.xaml b/samples/ControlCatalog/Pages/TextBoxPage.xaml index 5317e46e81..df410c2116 100644 --- a/samples/ControlCatalog/Pages/TextBoxPage.xaml +++ b/samples/ControlCatalog/Pages/TextBoxPage.xaml @@ -1,18 +1,6 @@ - - - - - - - - - - TextBox A control into which the user can input text diff --git a/src/Avalonia.Themes.Default/TextBox.xaml b/src/Avalonia.Themes.Default/TextBox.xaml index 8384cccada..e9d5857d67 100644 --- a/src/Avalonia.Themes.Default/TextBox.xaml +++ b/src/Avalonia.Themes.Default/TextBox.xaml @@ -1,4 +1,11 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From aa5bc078a7782908560865c3682cbd387acd7708 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 18 Aug 2020 14:59:22 -0700 Subject: [PATCH 233/344] Re-enable SharpGenTools.Sdk to patch calli but disable codegen (#4512) --- src/Avalonia.Native/Avalonia.Native.csproj | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Native/Avalonia.Native.csproj b/src/Avalonia.Native/Avalonia.Native.csproj index 9c3eaed2d8..f084411c2f 100644 --- a/src/Avalonia.Native/Avalonia.Native.csproj +++ b/src/Avalonia.Native/Avalonia.Native.csproj @@ -7,6 +7,7 @@ /usr/bin/castxml /usr/local/bin/castxml true + false @@ -18,8 +19,8 @@ - - + + From cd180770fbd46ff4f33721ed5ca81f477c72c0db Mon Sep 17 00:00:00 2001 From: Kiminuo Date: Wed, 19 Aug 2020 12:33:14 +0200 Subject: [PATCH 234/344] AppBuilderBase: Allow to specify app factory. --- src/Avalonia.Controls/AppBuilderBase.cs | 17 +++++++ .../AppBuilderTests.cs | 44 ++++++++++++++++++- 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/AppBuilderBase.cs b/src/Avalonia.Controls/AppBuilderBase.cs index d69052ad3d..f616a42cac 100644 --- a/src/Avalonia.Controls/AppBuilderBase.cs +++ b/src/Avalonia.Controls/AppBuilderBase.cs @@ -88,6 +88,23 @@ namespace Avalonia.Controls }; } + /// + /// Begin configuring an . + /// + /// Factory function for . + /// The subclass of to configure. + /// is useful for passing of dependencies to . + /// An instance. + public static TAppBuilder Configure(Func appFactory) + where TApp : Application + { + return new TAppBuilder() + { + ApplicationType = typeof(TApp), + _appFactory = appFactory + }; + } + protected TAppBuilder Self => (TAppBuilder)this; public TAppBuilder AfterSetup(Action callback) diff --git a/tests/Avalonia.Controls.UnitTests/AppBuilderTests.cs b/tests/Avalonia.Controls.UnitTests/AppBuilderTests.cs index b5004bc6a5..06ec9158fe 100644 --- a/tests/Avalonia.Controls.UnitTests/AppBuilderTests.cs +++ b/tests/Avalonia.Controls.UnitTests/AppBuilderTests.cs @@ -1,4 +1,5 @@ -using Avalonia.Controls.UnitTests; +using System; +using Avalonia.Controls.UnitTests; using Avalonia.Platform; using Xunit; @@ -18,6 +19,22 @@ namespace Avalonia.Controls.UnitTests { } + public class AppWithDependencies : Application + { + public AppWithDependencies() + { + throw new NotSupportedException(); + } + + public AppWithDependencies(object dependencyA, object dependencyB) + { + DependencyA = dependencyA; + DependencyB = dependencyB; + } + public object DependencyA { get; } + public object DependencyB { get; } + } + public class DefaultModule { public static bool IsLoaded = false; @@ -53,7 +70,30 @@ namespace Avalonia.Controls.UnitTests IsLoaded = true; } } - + + [Fact] + public void UseAppFactory() + { + using (AvaloniaLocator.EnterScope()) + { + ResetModuleLoadStates(); + + Func appFactory = () => new AppWithDependencies(dependencyA: new object(), dependencyB: new object()); + + var builder = AppBuilder.Configure(appFactory) + .UseWindowingSubsystem(() => { }) + .UseRenderingSubsystem(() => { }) + .UseAvaloniaModules() + .SetupWithoutStarting(); + + AppWithDependencies app = (AppWithDependencies)builder.Instance; + Assert.NotNull(app.DependencyA); + Assert.NotNull(app.DependencyB); + + Assert.True(DefaultModule.IsLoaded); + } + } + [Fact] public void LoadsDefaultModule() { From 793f1b7453993255f544a9ae561187896ccc24ac Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Tue, 9 Jun 2020 17:44:05 +0200 Subject: [PATCH 235/344] Allow support at CanExecute when binding a method --- .../AlwaysEnabledDelegateCommand.cs | 41 ---- .../Data/Converters/DefaultValueConverter.cs | 2 +- .../Converters/MethodToCommandConverter.cs | 182 ++++++++++++++++++ .../Metadata/DependsOnAttribute.cs | 2 +- 4 files changed, 184 insertions(+), 43 deletions(-) delete mode 100644 src/Avalonia.Base/Data/Converters/AlwaysEnabledDelegateCommand.cs create mode 100644 src/Avalonia.Base/Data/Converters/MethodToCommandConverter.cs diff --git a/src/Avalonia.Base/Data/Converters/AlwaysEnabledDelegateCommand.cs b/src/Avalonia.Base/Data/Converters/AlwaysEnabledDelegateCommand.cs deleted file mode 100644 index 7f4c83772d..0000000000 --- a/src/Avalonia.Base/Data/Converters/AlwaysEnabledDelegateCommand.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Globalization; -using System.Reflection; -using System.Windows.Input; -using Avalonia.Utilities; - -namespace Avalonia.Data.Converters -{ - class AlwaysEnabledDelegateCommand : ICommand - { - private readonly Delegate action; - - private ParameterInfo parameterInfo; - - public AlwaysEnabledDelegateCommand(Delegate action) - { - this.action = action; - var parameters = action.Method.GetParameters(); - parameterInfo = parameters.Length == 0 ? null : parameters[0]; - } - -#pragma warning disable 0067 - public event EventHandler CanExecuteChanged; -#pragma warning restore 0067 - - public bool CanExecute(object parameter) => true; - - public void Execute(object parameter) - { - if (parameterInfo == null) - { - action.DynamicInvoke(); - } - else - { - TypeUtilities.TryConvert(parameterInfo.ParameterType, parameter, CultureInfo.CurrentCulture, out object convertedParameter); - action.DynamicInvoke(convertedParameter); - } - } - } -} diff --git a/src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs b/src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs index 5e80a15059..83f7e02c16 100644 --- a/src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs +++ b/src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs @@ -33,7 +33,7 @@ namespace Avalonia.Data.Converters if (typeof(ICommand).IsAssignableFrom(targetType) && value is Delegate d && d.Method.GetParameters().Length <= 1) { - return new AlwaysEnabledDelegateCommand(d); + return new MethodToCommandConverter(d); } if (TypeUtilities.TryConvert(targetType, value, culture, out object result)) diff --git a/src/Avalonia.Base/Data/Converters/MethodToCommandConverter.cs b/src/Avalonia.Base/Data/Converters/MethodToCommandConverter.cs new file mode 100644 index 0000000000..c638fe56e6 --- /dev/null +++ b/src/Avalonia.Base/Data/Converters/MethodToCommandConverter.cs @@ -0,0 +1,182 @@ +using System; +using System.Globalization; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Windows.Input; +using Avalonia.Utilities; + +namespace Avalonia.Data.Converters +{ + class MethodToCommandConverter : ICommand + { + readonly static Func AlwaysEnabled = (_) => true; + readonly static MethodInfo tryConvert = typeof(TypeUtilities) + .GetMethod(nameof(TypeUtilities.TryConvert), BindingFlags.Public | BindingFlags.Static); + readonly static PropertyInfo currentCulture = typeof(CultureInfo) + .GetProperty(nameof(CultureInfo.CurrentCulture), BindingFlags.Public | BindingFlags.Static); + readonly Func canExecute; + readonly Action execute; + + public MethodToCommandConverter(Delegate action) + { + var target = action.Target; + var canExecuteMethodName = "Can" + action.Method.Name; + var parameters = action.Method.GetParameters(); + var parameterInfo = parameters.Length == 0 ? null : parameters[0].ParameterType; + + if (parameterInfo == null) + { + execute = CreateExecute(target, action.Method); + } + else + { + execute = CreateExecute(target, action.Method, parameterInfo); + } + + var canExecuteMethod = action.Method.DeclaringType.GetRuntimeMethods() + .FirstOrDefault(m => m.Name == canExecuteMethodName + && m.GetParameters().Length == 1 + && m.GetParameters()[0].ParameterType == typeof(object)); + if (canExecuteMethod == null) + { + canExecute = AlwaysEnabled; + } + else + { + canExecute = CreateCanExecute(target, canExecuteMethod); + var dependencyProperties = canExecuteMethod + .GetCustomAttributes(typeof(Metadata.DependsOnAttribute), true) + .OfType() + .Select(x => x.Name) + .ToArray(); + if (dependencyProperties.Any() + && target is System.ComponentModel.INotifyPropertyChanged inpc) + { + System.ComponentModel.PropertyChangedEventHandler invalidateCanExecuteHandler = (s, e) => + { + if (string.IsNullOrWhiteSpace(e.PropertyName) + || dependencyProperties.Contains(e.PropertyName)) + { + Threading.Dispatcher.UIThread.Post(() => CanExecuteChanged?.Invoke(this, EventArgs.Empty) + , Threading.DispatcherPriority.Input); + } + }; + inpc.PropertyChanged += invalidateCanExecuteHandler; + } + } + + + } + +#pragma warning disable 0067 + public event EventHandler CanExecuteChanged; +#pragma warning restore 0067 + + public bool CanExecute(object parameter) => canExecute(parameter); + + public void Execute(object parameter) => execute(parameter); + + + static Action CreateExecute(object target + , System.Reflection.MethodInfo method) + { + + var parameter = Expression.Parameter(typeof(object), "parameter"); + + var instance = Expression.Convert + ( + Expression.Constant(target), + method.DeclaringType + ); + + + var call = Expression.Call + ( + instance, + method + ); + + + return Expression + .Lambda>(call, parameter) + .Compile(); + } + + static Action CreateExecute(object target + , System.Reflection.MethodInfo method + , Type parameterType) + { + + var parameter = Expression.Parameter(typeof(object), "parameter"); + + var instance = Expression.Convert + ( + Expression.Constant(target), + method.DeclaringType + ); + + Expression body; + + if (parameterType == typeof(object)) + { + body = Expression.Call(instance, + method, + parameter + ); + } + else + { + var arg0 = Expression.Variable(typeof(object), "argX"); + var convertCall = Expression.Call(tryConvert, + Expression.Constant(parameterType), + parameter, + Expression.Property(null, currentCulture), + arg0 + ); + + var call = Expression.Call(instance, + method, + Expression.Convert(arg0, parameterType) + ); + body = Expression.Block(new[] { arg0 }, + convertCall, + call + ); + + } + Action action = null; + try + { + action = Expression + .Lambda>(body, parameter) + .Compile(); + } + catch (Exception ex) + { + throw ex; + } + return action; + } + + static Func CreateCanExecute(object target + , System.Reflection.MethodInfo method) + { + var parameter = Expression.Parameter(typeof(object), "parameter"); + var instance = Expression.Convert + ( + Expression.Constant(target), + method.DeclaringType + ); + var call = Expression.Call + ( + instance, + method, + parameter + ); + return Expression + .Lambda>(call, parameter) + .Compile(); + } + } +} diff --git a/src/Avalonia.Base/Metadata/DependsOnAttribute.cs b/src/Avalonia.Base/Metadata/DependsOnAttribute.cs index 92c6a58170..caee71ebfd 100644 --- a/src/Avalonia.Base/Metadata/DependsOnAttribute.cs +++ b/src/Avalonia.Base/Metadata/DependsOnAttribute.cs @@ -5,7 +5,7 @@ namespace Avalonia.Metadata /// /// Indicates that the property depends on the value of another property in markup. /// - [AttributeUsage(AttributeTargets.Property)] + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Method, Inherited = true, AllowMultiple = true)] public class DependsOnAttribute : Attribute { /// From 9f3ed1c8fe1de02fd8e98cb43ed5eb5c2575676a Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Tue, 9 Jun 2020 17:44:45 +0200 Subject: [PATCH 236/344] Add testing --- .../Data/BindingTests_Method.cs | 100 +++++++++++++++++- 1 file changed, 96 insertions(+), 4 deletions(-) diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests_Method.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests_Method.cs index a7a004bd49..e1a7803821 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests_Method.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests_Method.cs @@ -1,5 +1,4 @@ -using System.Reactive.Subjects; -using System.Windows.Input; +using System.ComponentModel; using Avalonia.Controls; using Avalonia.Input; using Avalonia.UnitTests; @@ -56,7 +55,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.Data Assert.Equal("Called 5", vm.Value); } } - + [Fact] public void Binding_Method_To_TextBlock_Text_Works() { @@ -79,6 +78,68 @@ namespace Avalonia.Markup.Xaml.UnitTests.Data } } + + [Theory] + [InlineData(null, "Not called")] + [InlineData("A", "Do A")] + public void Binding_Method_With_Parameter_To_Command_CanExecute(object commandParameter, string result) + { + using (UnitTestApplication.Start(TestServices.StyledWindow)) + { + var xaml = @" + +