From 05361cdb748a29d67d480246702544165fa1c0bd Mon Sep 17 00:00:00 2001 From: Luis von der Eltz Date: Mon, 5 Jul 2021 15:56:34 +0200 Subject: [PATCH 01/26] Adding option to inspect Popup visual tree --- .../Diagnostics/ViewModels/MainViewModel.cs | 1 - .../Diagnostics/ViewModels/VisualTreeNode.cs | 30 ++++-- .../Diagnostics/Views/MainWindow.xaml.cs | 91 ++++++++++++------- 3 files changed, 81 insertions(+), 41 deletions(-) diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs index 3f367165ac..07ae222a9c 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs @@ -1,6 +1,5 @@ using System; using System.ComponentModel; - using Avalonia.Controls; using Avalonia.Diagnostics.Models; using Avalonia.Input; diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/VisualTreeNode.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/VisualTreeNode.cs index 48fa636664..b9981babf7 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/VisualTreeNode.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/VisualTreeNode.cs @@ -1,5 +1,6 @@ using System; using Avalonia.Collections; +using Avalonia.Controls.Primitives; using Avalonia.Styling; using Avalonia.VisualTree; @@ -24,8 +25,7 @@ namespace Avalonia.Diagnostics.ViewModels public static VisualTreeNode[] Create(object control) { - var visual = control as IVisual; - return visual != null ? new[] { new VisualTreeNode(visual, null) } : Array.Empty(); + return control is IVisual visual ? new[] { new VisualTreeNode(visual, null) } : Array.Empty(); } internal class VisualTreeNodeCollection : TreeNodeCollection @@ -46,10 +46,28 @@ namespace Avalonia.Diagnostics.ViewModels protected override void Initialize(AvaloniaList nodes) { - _subscription = _control.VisualChildren.ForEachItem( - (i, item) => nodes.Insert(i, new VisualTreeNode(item, Owner)), - (i, item) => nodes.RemoveAt(i), - () => nodes.Clear()); + if (_control is Popup p) + { + _subscription = p.GetObservable(Popup.ChildProperty).Subscribe(child => + { + if (child != null) + { + nodes.Add(new VisualTreeNode(child, Owner)); + } + else + { + nodes.Clear(); + } + + }); + } + else + { + _subscription = _control.VisualChildren.ForEachItem( + (i, item) => nodes.Insert(i, new VisualTreeNode(item, Owner)), + (i, item) => nodes.RemoveAt(i), + () => nodes.Clear()); + } } } } diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs b/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs index d1232b749a..9d37b5acdc 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs @@ -27,19 +27,19 @@ namespace Avalonia.Diagnostics.Views EventHandler? lh = default; lh = (s, e) => - { - this.Opened -= lh; - if ((DataContext as MainViewModel)?.StartupScreenIndex is int index) - { - var screens = this.Screens; - if (index > -1 && index < screens.ScreenCount) - { - var screen = screens.All[index]; - this.Position = screen.Bounds.TopLeft; - this.WindowState = WindowState.Maximized; - } - } - }; + { + this.Opened -= lh; + if ((DataContext as MainViewModel)?.StartupScreenIndex is { } index) + { + var screens = this.Screens; + if (index > -1 && index < screens.ScreenCount) + { + var screen = screens.All[index]; + this.Position = screen.Bounds.TopLeft; + this.WindowState = WindowState.Maximized; + } + } + }; this.Opened += lh; } @@ -91,6 +91,24 @@ namespace Avalonia.Diagnostics.Views AvaloniaXamlLoader.Load(this); } + private IControl? GetHoveredControl(TopLevel topLevel) + { +#pragma warning disable CS0618 // Type or member is obsolete + var point = (topLevel as IInputRoot)?.MouseDevice?.GetPosition(topLevel) ?? default; +#pragma warning restore CS0618 // Type or member is obsolete + + return (IControl?)topLevel.GetVisualsAt(point, x => + { + if (x is AdornerLayer || !x.IsVisible) + { + return false; + } + + return !(x is IInputElement ie) || ie.IsHitTestVisible; + }) + .FirstOrDefault(); + } + private void RawKeyDown(RawKeyEventArgs e) { var vm = (MainViewModel?)DataContext; @@ -99,34 +117,39 @@ namespace Avalonia.Diagnostics.Views return; } - const RawInputModifiers modifiers = RawInputModifiers.Control | RawInputModifiers.Shift; - - if (e.Modifiers == modifiers) + switch (e.Modifiers) { -#pragma warning disable CS0618 // Type or member is obsolete - var point = (Root as IInputRoot)?.MouseDevice?.GetPosition(Root) ?? default; -#pragma warning restore CS0618 // Type or member is obsolete + case RawInputModifiers.Control | RawInputModifiers.Shift: + { + IControl? control = null; - var control = Root.GetVisualsAt(point, x => + foreach (var popup in Root.GetVisualDescendants().OfType()) { - if (x is AdornerLayer || !x.IsVisible) return false; - if (!(x is IInputElement ie)) return true; - return ie.IsHitTestVisible; - }) - .FirstOrDefault(); + if (popup.Host?.HostedVisualTreeRoot is PopupRoot popupRoot) + { + control = GetHoveredControl(popupRoot); + + if (control != null) + { + break; + } + } + } - if (control != null) - { - vm.SelectControl((IControl)control); + control ??= GetHoveredControl(Root); + + if (control != null) + { + vm.SelectControl(control); + } + + break; } - } - else if (e.Modifiers == RawInputModifiers.Alt) - { - if (e.Key == Key.S || e.Key == Key.D) + case RawInputModifiers.Alt when e.Key == Key.S || e.Key == Key.D: { - var enable = e.Key == Key.S; + vm.EnableSnapshotStyles(e.Key == Key.S); - vm.EnableSnapshotStyles(enable); + break; } } } From 31d80a9fb67165417d327e008190bb0344563aae Mon Sep 17 00:00:00 2001 From: Luis von der Eltz Date: Tue, 6 Jul 2021 10:30:24 +0200 Subject: [PATCH 02/26] Make tree roots bold --- .../Diagnostics/ViewModels/TreeNode.cs | 25 ++++++------------- .../Diagnostics/Views/TreePageView.xaml | 2 +- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs index 4cb470eeac..14d704db93 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs @@ -4,24 +4,28 @@ using System.Collections.Specialized; using System.Reactive; using System.Reactive.Linq; using Avalonia.Controls; +using Avalonia.Controls.Primitives; using Avalonia.LogicalTree; +using Avalonia.Media; using Avalonia.VisualTree; namespace Avalonia.Diagnostics.ViewModels { internal abstract class TreeNode : ViewModelBase, IDisposable { - private IDisposable? _classesSubscription; + private readonly IDisposable? _classesSubscription; private string _classes; private bool _isExpanded; - public TreeNode(IVisual visual, TreeNode? parent) + protected TreeNode(IVisual visual, TreeNode? parent) { Parent = parent; Type = visual.GetType().Name; Visual = visual; _classes = string.Empty; + FontWeight = Visual is TopLevel or Popup ? FontWeight.Bold : FontWeight.Normal; + if (visual is IControl control) { ElementName = control.Name; @@ -52,6 +56,8 @@ namespace Avalonia.Diagnostics.ViewModels } } + public FontWeight FontWeight { get; } + public abstract TreeNodeCollection Children { get; @@ -95,20 +101,5 @@ namespace Avalonia.Diagnostics.ViewModels _classesSubscription?.Dispose(); Children.Dispose(); } - - private static int IndexOf(IReadOnlyList collection, TreeNode item) - { - var count = collection.Count; - - for (var i = 0; i < count; ++i) - { - if (collection[i] == item) - { - return i; - } - } - - throw new AvaloniaInternalException("TreeNode was not present in parent Children collection."); - } } } diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/TreePageView.xaml b/src/Avalonia.Diagnostics/Diagnostics/Views/TreePageView.xaml index a5328716fc..bb661f7f4c 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Views/TreePageView.xaml +++ b/src/Avalonia.Diagnostics/Diagnostics/Views/TreePageView.xaml @@ -11,7 +11,7 @@ - + From cd56e1a9fc6e914571b2b38ab042fcc0275feaeb Mon Sep 17 00:00:00 2001 From: Luis von der Eltz Date: Tue, 6 Jul 2021 10:40:07 +0200 Subject: [PATCH 03/26] Remove "or" --- src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs index 14d704db93..f4c04dbca6 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs @@ -24,7 +24,7 @@ namespace Avalonia.Diagnostics.ViewModels Visual = visual; _classes = string.Empty; - FontWeight = Visual is TopLevel or Popup ? FontWeight.Bold : FontWeight.Normal; + FontWeight = Visual is TopLevel || Visual is Popup ? FontWeight.Bold : FontWeight.Normal; if (visual is IControl control) { From a9affd64bf67d2ff39e3853b7f0adc168be71f3f Mon Sep 17 00:00:00 2001 From: Luis von der Eltz Date: Thu, 15 Jul 2021 15:46:47 +0200 Subject: [PATCH 04/26] Add support for Flyouts, ToolTips & ContextMenus --- .../Diagnostics/IPopupHostProvider.cs | 23 +++++ .../Diagnostics/ToolTipDiagnostics.cs | 12 +++ src/Avalonia.Controls/Flyouts/FlyoutBase.cs | 25 ++++- src/Avalonia.Controls/ToolTip.cs | 40 +++++--- .../Diagnostics/ViewModels/TreeNode.cs | 11 ++- .../Diagnostics/ViewModels/VisualTreeNode.cs | 97 ++++++++++++++----- 6 files changed, 163 insertions(+), 45 deletions(-) create mode 100644 src/Avalonia.Controls/Diagnostics/IPopupHostProvider.cs create mode 100644 src/Avalonia.Controls/Diagnostics/ToolTipDiagnostics.cs diff --git a/src/Avalonia.Controls/Diagnostics/IPopupHostProvider.cs b/src/Avalonia.Controls/Diagnostics/IPopupHostProvider.cs new file mode 100644 index 0000000000..11d3b1792a --- /dev/null +++ b/src/Avalonia.Controls/Diagnostics/IPopupHostProvider.cs @@ -0,0 +1,23 @@ +using System; +using Avalonia.Controls.Primitives; + +#nullable enable + +namespace Avalonia.Controls.Diagnostics +{ + /// + /// Diagnostics interface to retrieve an associated . + /// + public interface IPopupHostProvider + { + /// + /// The popup host. + /// + IPopupHost? PopupHost { get; } + + /// + /// Raised when the popup host changes. + /// + event Action? PopupHostChanged; + } +} diff --git a/src/Avalonia.Controls/Diagnostics/ToolTipDiagnostics.cs b/src/Avalonia.Controls/Diagnostics/ToolTipDiagnostics.cs new file mode 100644 index 0000000000..58174b1039 --- /dev/null +++ b/src/Avalonia.Controls/Diagnostics/ToolTipDiagnostics.cs @@ -0,0 +1,12 @@ +#nullable enable + +namespace Avalonia.Controls.Diagnostics +{ + /// + /// Helper class to provide some diagnostics insides into . + /// + public static class ToolTipDiagnostics + { + public static AvaloniaProperty ToolTipProperty = ToolTip.ToolTipProperty; + } +} diff --git a/src/Avalonia.Controls/Flyouts/FlyoutBase.cs b/src/Avalonia.Controls/Flyouts/FlyoutBase.cs index e4b68c62fd..6b72b8c887 100644 --- a/src/Avalonia.Controls/Flyouts/FlyoutBase.cs +++ b/src/Avalonia.Controls/Flyouts/FlyoutBase.cs @@ -1,16 +1,16 @@ using System; using System.ComponentModel; +using Avalonia.Controls.Diagnostics; using Avalonia.Input; using Avalonia.Input.Raw; using Avalonia.Layout; using Avalonia.Logging; -using Avalonia.Rendering; #nullable enable namespace Avalonia.Controls.Primitives { - public abstract class FlyoutBase : AvaloniaObject + public abstract class FlyoutBase : AvaloniaObject, IPopupHostProvider { static FlyoutBase() { @@ -55,6 +55,7 @@ namespace Avalonia.Controls.Primitives private Rect? _enlargedPopupRect; private PixelRect? _enlargePopupRectScreenPixelRect; private IDisposable? _transientDisposable; + private Action? _popupHostChangedHandler; protected Popup? Popup { get; private set; } @@ -94,6 +95,14 @@ namespace Avalonia.Controls.Primitives private set => SetAndRaise(TargetProperty, ref _target, value); } + IPopupHost? IPopupHostProvider.PopupHost => Popup?.Host; + + event Action? IPopupHostProvider.PopupHostChanged + { + add => _popupHostChangedHandler += value; + remove => _popupHostChangedHandler -= value; + } + public event EventHandler? Closed; public event EventHandler? Closing; public event EventHandler? Opened; @@ -322,9 +331,11 @@ namespace Avalonia.Controls.Primitives private void InitPopup() { - Popup = new Popup(); - Popup.WindowManagerAddShadowHint = false; - Popup.IsLightDismissEnabled = true; + Popup = new Popup + { + WindowManagerAddShadowHint = false, + IsLightDismissEnabled = true + }; Popup.Opened += OnPopupOpened; Popup.Closed += OnPopupClosed; @@ -333,11 +344,15 @@ namespace Avalonia.Controls.Primitives private void OnPopupOpened(object sender, EventArgs e) { IsOpen = true; + + _popupHostChangedHandler?.Invoke(Popup!.Host); } private void OnPopupClosed(object sender, EventArgs e) { HideCore(); + + _popupHostChangedHandler?.Invoke(null); } private void PositionPopup(bool showAtPointer) diff --git a/src/Avalonia.Controls/ToolTip.cs b/src/Avalonia.Controls/ToolTip.cs index ab507d07a2..ab310d60ef 100644 --- a/src/Avalonia.Controls/ToolTip.cs +++ b/src/Avalonia.Controls/ToolTip.cs @@ -1,9 +1,8 @@ #nullable enable using System; -using System.Reactive.Linq; +using Avalonia.Controls.Diagnostics; using Avalonia.Controls.Metadata; using Avalonia.Controls.Primitives; -using Avalonia.VisualTree; namespace Avalonia.Controls { @@ -17,7 +16,7 @@ namespace Avalonia.Controls /// assigning the content that you want displayed. /// [PseudoClasses(":open")] - public class ToolTip : ContentControl + public class ToolTip : ContentControl, IPopupHostProvider { /// /// Defines the ToolTip.Tip attached property. @@ -61,7 +60,8 @@ namespace Avalonia.Controls internal static readonly AttachedProperty ToolTipProperty = AvaloniaProperty.RegisterAttached("ToolTip"); - private IPopupHost? _popup; + private IPopupHost? _popupHost; + private Action? _popupHostChangedHandler; /// /// Initializes static members of the class. @@ -251,35 +251,45 @@ namespace Avalonia.Controls tooltip.RecalculatePosition(control); } + + IPopupHost? IPopupHostProvider.PopupHost => _popupHost; + + event Action? IPopupHostProvider.PopupHostChanged + { + add => _popupHostChangedHandler += value; + remove => _popupHostChangedHandler -= value; + } internal void RecalculatePosition(Control control) { - _popup?.ConfigurePosition(control, GetPlacement(control), new Point(GetHorizontalOffset(control), GetVerticalOffset(control))); + _popupHost?.ConfigurePosition(control, GetPlacement(control), new Point(GetHorizontalOffset(control), GetVerticalOffset(control))); } private void Open(Control control) { Close(); - _popup = OverlayPopupHost.CreatePopupHost(control, null); - _popup.SetChild(this); - ((ISetLogicalParent)_popup).SetParent(control); + _popupHost = OverlayPopupHost.CreatePopupHost(control, null); + _popupHost.SetChild(this); + ((ISetLogicalParent)_popupHost).SetParent(control); - _popup.ConfigurePosition(control, GetPlacement(control), + _popupHost.ConfigurePosition(control, GetPlacement(control), new Point(GetHorizontalOffset(control), GetVerticalOffset(control))); - WindowManagerAddShadowHintChanged(_popup, false); + WindowManagerAddShadowHintChanged(_popupHost, false); - _popup.Show(); + _popupHost.Show(); + _popupHostChangedHandler?.Invoke(_popupHost); } private void Close() { - if (_popup != null) + if (_popupHost != null) { - _popup.SetChild(null); - _popup.Dispose(); - _popup = null; + _popupHost.SetChild(null); + _popupHost.Dispose(); + _popupHost = null; + _popupHostChangedHandler?.Invoke(null); } } diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs index f4c04dbca6..9667751e54 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs @@ -4,6 +4,7 @@ using System.Collections.Specialized; using System.Reactive; using System.Reactive.Linq; using Avalonia.Controls; +using Avalonia.Controls.Diagnostics; using Avalonia.Controls.Primitives; using Avalonia.LogicalTree; using Avalonia.Media; @@ -19,12 +20,11 @@ namespace Avalonia.Diagnostics.ViewModels protected TreeNode(IVisual visual, TreeNode? parent) { + _classes = string.Empty; Parent = parent; Type = visual.GetType().Name; Visual = visual; - _classes = string.Empty; - - FontWeight = Visual is TopLevel || Visual is Popup ? FontWeight.Bold : FontWeight.Normal; + FontWeight = IsRoot ? FontWeight.Bold : FontWeight.Normal; if (visual is IControl control) { @@ -56,6 +56,11 @@ namespace Avalonia.Diagnostics.ViewModels } } + private bool IsRoot => Visual is TopLevel || + Visual is Popup || + Visual is ContextMenu || + Visual is IPopupHost; + public FontWeight FontWeight { get; } public abstract TreeNodeCollection Children diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/VisualTreeNode.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/VisualTreeNode.cs index b9981babf7..6d803a1a7b 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/VisualTreeNode.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/VisualTreeNode.cs @@ -1,5 +1,10 @@ using System; +using System.Reactive.Disposables; +using System.Reactive.Linq; +using System.Security.Cryptography.X509Certificates; using Avalonia.Collections; +using Avalonia.Controls; +using Avalonia.Controls.Diagnostics; using Avalonia.Controls.Primitives; using Avalonia.Styling; using Avalonia.VisualTree; @@ -13,7 +18,7 @@ namespace Avalonia.Diagnostics.ViewModels { Children = new VisualTreeNodeCollection(this, visual); - if ((Visual is IStyleable styleable)) + if (Visual is IStyleable styleable) { IsInTemplate = styleable.TemplatedParent != null; } @@ -25,13 +30,15 @@ namespace Avalonia.Diagnostics.ViewModels public static VisualTreeNode[] Create(object control) { - return control is IVisual visual ? new[] { new VisualTreeNode(visual, null) } : Array.Empty(); + return control is IVisual visual ? + new[] { new VisualTreeNode(visual, null) } : + Array.Empty(); } internal class VisualTreeNodeCollection : TreeNodeCollection { private readonly IVisual _control; - private IDisposable? _subscription; + private readonly CompositeDisposable _subscriptions = new CompositeDisposable(2); public VisualTreeNodeCollection(TreeNode owner, IVisual control) : base(owner) @@ -41,33 +48,79 @@ namespace Avalonia.Diagnostics.ViewModels public override void Dispose() { - _subscription?.Dispose(); + _subscriptions.Dispose(); } - protected override void Initialize(AvaloniaList nodes) + private static IObservable? GetHostedPopupRootObservable(IVisual visual) { - if (_control is Popup p) + static IObservable GetPopupHostObservable(IPopupHostProvider popupHostProvider) { - _subscription = p.GetObservable(Popup.ChildProperty).Subscribe(child => - { - if (child != null) - { - nodes.Add(new VisualTreeNode(child, Owner)); - } - else - { - nodes.Clear(); - } - - }); + return Observable.FromEvent( + x => popupHostProvider.PopupHostChanged += x, + x => popupHostProvider.PopupHostChanged -= x) + .StartWith(popupHostProvider.PopupHost) + .Select(x => x is IControl c ? c : null); } - else + + return visual switch { - _subscription = _control.VisualChildren.ForEachItem( + Popup p => p.GetObservable(Popup.ChildProperty), + Control c => Observable.CombineLatest( + c.GetObservable(Control.ContextFlyoutProperty), + c.GetObservable(Control.ContextMenuProperty), + c.GetObservable(FlyoutBase.AttachedFlyoutProperty), + c.GetObservable(ToolTipDiagnostics.ToolTipProperty), + (ContextFlyout, ContextMenu, AttachedFlyout, ToolTip) => + { + if (ContextMenu != null) + { + //Note: ContextMenus are special since all the items are added as visual children. + //So we don't need to go via Popup + return Observable.Return(ContextMenu); + } + + if ((ContextFlyout ?? (IPopupHostProvider?) AttachedFlyout ?? ToolTip) is { } popupHostProvider) + { + return GetPopupHostObservable(popupHostProvider); + } + + return Observable.Return(null); + }) + .Switch(), + _ => null + }; + } + + protected override void Initialize(AvaloniaList nodes) + { + _subscriptions.Clear(); + + if (GetHostedPopupRootObservable(_control) is { } popupRootObservable) + { + VisualTreeNode? childNode = null; + + _subscriptions.Add( + popupRootObservable + .Subscribe(root => + { + if (root != null) + { + childNode = new VisualTreeNode(root, Owner); + + nodes.Add(childNode); + } + else if (childNode != null) + { + nodes.Remove(childNode); + } + })); + } + + _subscriptions.Add( + _control.VisualChildren.ForEachItem( (i, item) => nodes.Insert(i, new VisualTreeNode(item, Owner)), (i, item) => nodes.RemoveAt(i), - () => nodes.Clear()); - } + () => nodes.Clear())); } } } From 4d9131091e04db53b53622238ade11f635a751e1 Mon Sep 17 00:00:00 2001 From: Luis von der Eltz Date: Thu, 15 Jul 2021 16:19:56 +0200 Subject: [PATCH 05/26] Add custom names to PopupRoot --- src/Avalonia.Controls/Primitives/Popup.cs | 17 ++++- .../Diagnostics/ViewModels/TreeNode.cs | 6 +- .../Diagnostics/ViewModels/VisualTreeNode.cs | 72 ++++++++++++------- 3 files changed, 65 insertions(+), 30 deletions(-) diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs index b445de0472..bdc71f9a62 100644 --- a/src/Avalonia.Controls/Primitives/Popup.cs +++ b/src/Avalonia.Controls/Primitives/Popup.cs @@ -1,6 +1,6 @@ using System; -using System.Linq; using System.Reactive.Disposables; +using Avalonia.Controls.Diagnostics; using Avalonia.Controls.Presenters; using Avalonia.Controls.Primitives.PopupPositioning; using Avalonia.Input; @@ -17,7 +17,7 @@ namespace Avalonia.Controls.Primitives /// /// Displays a popup window. /// - public class Popup : Control, IVisualTreeHost + public class Popup : Control, IVisualTreeHost, IPopupHostProvider { public static readonly StyledProperty WindowManagerAddShadowHintProperty = AvaloniaProperty.Register(nameof(WindowManagerAddShadowHint), true); @@ -133,6 +133,7 @@ namespace Avalonia.Controls.Primitives private bool _ignoreIsOpenChanged; private PopupOpenState? _openState; private IInputElement _overlayInputPassThroughElement; + private Action? _popupHostChangedHandler; /// /// Initializes static members of the class. @@ -348,6 +349,14 @@ namespace Avalonia.Controls.Primitives /// IVisual? IVisualTreeHost.Root => _openState?.PopupHost.HostedVisualTreeRoot; + IPopupHost? IPopupHostProvider.PopupHost => Host; + + event Action? IPopupHostProvider.PopupHostChanged + { + add => _popupHostChangedHandler += value; + remove => _popupHostChangedHandler -= value; + } + /// /// Opens the popup. /// @@ -479,6 +488,8 @@ namespace Avalonia.Controls.Primitives } Opened?.Invoke(this, EventArgs.Empty); + + _popupHostChangedHandler?.Invoke(Host); } /// @@ -581,6 +592,8 @@ namespace Avalonia.Controls.Primitives _openState.Dispose(); _openState = null; + _popupHostChangedHandler?.Invoke(null); + using (BeginIgnoringIsOpen()) { IsOpen = false; diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs index 9667751e54..4b957c2382 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs @@ -1,10 +1,8 @@ using System; -using System.Collections.Generic; using System.Collections.Specialized; using System.Reactive; using System.Reactive.Linq; using Avalonia.Controls; -using Avalonia.Controls.Diagnostics; using Avalonia.Controls.Primitives; using Avalonia.LogicalTree; using Avalonia.Media; @@ -18,11 +16,11 @@ namespace Avalonia.Diagnostics.ViewModels private string _classes; private bool _isExpanded; - protected TreeNode(IVisual visual, TreeNode? parent) + protected TreeNode(IVisual visual, TreeNode? parent, string? customName = null) { _classes = string.Empty; Parent = parent; - Type = visual.GetType().Name; + Type = customName ?? visual.GetType().Name; Visual = visual; FontWeight = IsRoot ? FontWeight.Bold : FontWeight.Normal; diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/VisualTreeNode.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/VisualTreeNode.cs index 6d803a1a7b..f03f16d18f 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/VisualTreeNode.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/VisualTreeNode.cs @@ -1,7 +1,7 @@ using System; +using System.Linq; using System.Reactive.Disposables; using System.Reactive.Linq; -using System.Security.Cryptography.X509Certificates; using Avalonia.Collections; using Avalonia.Controls; using Avalonia.Controls.Diagnostics; @@ -13,18 +13,15 @@ namespace Avalonia.Diagnostics.ViewModels { internal class VisualTreeNode : TreeNode { - public VisualTreeNode(IVisual visual, TreeNode? parent) - : base(visual, parent) + public VisualTreeNode(IVisual visual, TreeNode? parent, string? customName = null) + : base(visual, parent, customName) { Children = new VisualTreeNodeCollection(this, visual); - if (Visual is IStyleable styleable) - { - IsInTemplate = styleable.TemplatedParent != null; - } + if (Visual is IStyleable styleable) IsInTemplate = styleable.TemplatedParent != null; } - public bool IsInTemplate { get; private set; } + public bool IsInTemplate { get; } public override TreeNodeCollection Children { get; } @@ -51,20 +48,30 @@ namespace Avalonia.Diagnostics.ViewModels _subscriptions.Dispose(); } - private static IObservable? GetHostedPopupRootObservable(IVisual visual) + private static IObservable? GetHostedPopupRootObservable(IVisual visual) { - static IObservable GetPopupHostObservable(IPopupHostProvider popupHostProvider) + static IObservable GetPopupHostObservable( + IPopupHostProvider popupHostProvider, + string? providerName = null) { return Observable.FromEvent( x => popupHostProvider.PopupHostChanged += x, x => popupHostProvider.PopupHostChanged -= x) .StartWith(popupHostProvider.PopupHost) - .Select(x => x is IControl c ? c : null); + .Select(popupHost => + { + if (popupHost is IControl control) + return new PopupRoot( + control, + providerName != null ? $"{providerName} ({control.GetType().Name})" : null); + + return (PopupRoot?)null; + }); } return visual switch { - Popup p => p.GetObservable(Popup.ChildProperty), + Popup p => GetPopupHostObservable(p), Control c => Observable.CombineLatest( c.GetObservable(Control.ContextFlyoutProperty), c.GetObservable(Control.ContextMenuProperty), @@ -73,18 +80,20 @@ namespace Avalonia.Diagnostics.ViewModels (ContextFlyout, ContextMenu, AttachedFlyout, ToolTip) => { if (ContextMenu != null) - { //Note: ContextMenus are special since all the items are added as visual children. //So we don't need to go via Popup - return Observable.Return(ContextMenu); - } + return Observable.Return(new PopupRoot(ContextMenu)); - if ((ContextFlyout ?? (IPopupHostProvider?) AttachedFlyout ?? ToolTip) is { } popupHostProvider) - { - return GetPopupHostObservable(popupHostProvider); - } + if (ContextFlyout != null) + return GetPopupHostObservable(ContextFlyout, "ContextFlyout"); + + if (AttachedFlyout != null) + return GetPopupHostObservable(AttachedFlyout, "AttachedFlyout"); + + if (ToolTip != null) + return GetPopupHostObservable(ToolTip, "ToolTip"); - return Observable.Return(null); + return Observable.Return(null); }) .Switch(), _ => null @@ -101,18 +110,21 @@ namespace Avalonia.Diagnostics.ViewModels _subscriptions.Add( popupRootObservable - .Subscribe(root => + .Subscribe(popupRoot => { - if (root != null) + if (popupRoot != null) { - childNode = new VisualTreeNode(root, Owner); + childNode = new VisualTreeNode( + popupRoot.Value.Root, + Owner, + popupRoot.Value.CustomName); nodes.Add(childNode); } else if (childNode != null) { nodes.Remove(childNode); - } + }s })); } @@ -122,6 +134,18 @@ namespace Avalonia.Diagnostics.ViewModels (i, item) => nodes.RemoveAt(i), () => nodes.Clear())); } + + private struct PopupRoot + { + public PopupRoot(IControl root, string? customName = null) + { + Root = root; + CustomName = customName; + } + + public IControl Root { get; } + public string? CustomName { get; } + } } } } From dfc5669507d6910c510a4a7619f377e0b02a5100 Mon Sep 17 00:00:00 2001 From: Luis von der Eltz Date: Thu, 15 Jul 2021 16:20:22 +0200 Subject: [PATCH 06/26] Typo --- .../Diagnostics/ViewModels/VisualTreeNode.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/VisualTreeNode.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/VisualTreeNode.cs index f03f16d18f..5524d06f1b 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/VisualTreeNode.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/VisualTreeNode.cs @@ -124,7 +124,7 @@ namespace Avalonia.Diagnostics.ViewModels else if (childNode != null) { nodes.Remove(childNode); - }s + } })); } From 650ae63bd641868decb2bce426a21aa88ad94496 Mon Sep 17 00:00:00 2001 From: Luis von der Eltz Date: Thu, 15 Jul 2021 17:46:00 +0200 Subject: [PATCH 07/26] make "ctrl+shift+click" work --- src/Avalonia.Controls/ContextMenu.cs | 17 ++++++- .../Diagnostics/ViewModels/VisualTreeNode.cs | 4 +- .../Diagnostics/Views/MainWindow.xaml.cs | 46 +++++++++++++++---- 3 files changed, 55 insertions(+), 12 deletions(-) diff --git a/src/Avalonia.Controls/ContextMenu.cs b/src/Avalonia.Controls/ContextMenu.cs index ead5b0d9f3..0c8fc31df1 100644 --- a/src/Avalonia.Controls/ContextMenu.cs +++ b/src/Avalonia.Controls/ContextMenu.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; - +using Avalonia.Controls.Diagnostics; using Avalonia.Controls.Generators; using Avalonia.Controls.Platform; using Avalonia.Controls.Primitives; @@ -21,7 +21,7 @@ namespace Avalonia.Controls /// /// A control context menu. /// - public class ContextMenu : MenuBase, ISetterValue + public class ContextMenu : MenuBase, ISetterValue, IPopupHostProvider { /// /// Defines the property. @@ -82,6 +82,7 @@ namespace Avalonia.Controls private Popup? _popup; private List? _attachedControls; private IInputElement? _previousFocus; + private Action? _popupHostChangedHandler; /// /// Initializes a new instance of the class. @@ -304,6 +305,14 @@ namespace Avalonia.Controls } } + IPopupHost? IPopupHostProvider.PopupHost => _popup?.Host; + + event Action? IPopupHostProvider.PopupHostChanged + { + add => _popupHostChangedHandler += value; + remove => _popupHostChangedHandler -= value; + } + protected override IItemContainerGenerator CreateItemContainerGenerator() { return new MenuItemContainerGenerator(this); @@ -364,6 +373,8 @@ namespace Avalonia.Controls { _previousFocus = FocusManager.Instance?.Current; Focus(); + + _popupHostChangedHandler?.Invoke(_popup!.Host); } private void PopupClosing(object sender, CancelEventArgs e) @@ -397,6 +408,8 @@ namespace Avalonia.Controls RoutedEvent = MenuClosedEvent, Source = this, }); + + _popupHostChangedHandler?.Invoke(null); } private void PopupKeyUp(object sender, KeyEventArgs e) diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/VisualTreeNode.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/VisualTreeNode.cs index 5524d06f1b..6a430897ba 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/VisualTreeNode.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/VisualTreeNode.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using System.Reactive.Disposables; using System.Reactive.Linq; using Avalonia.Collections; @@ -18,7 +17,8 @@ namespace Avalonia.Diagnostics.ViewModels { Children = new VisualTreeNodeCollection(this, visual); - if (Visual is IStyleable styleable) IsInTemplate = styleable.TemplatedParent != null; + if (Visual is IStyleable styleable) + IsInTemplate = styleable.TemplatedParent != null; } public bool IsInTemplate { get; } diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs b/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs index 9d37b5acdc..26e197d790 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs @@ -1,7 +1,9 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Reactive.Linq; using Avalonia.Controls; +using Avalonia.Controls.Diagnostics; using Avalonia.Controls.Primitives; using Avalonia.Diagnostics.ViewModels; using Avalonia.Input; @@ -109,6 +111,37 @@ namespace Avalonia.Diagnostics.Views .FirstOrDefault(); } + private static IEnumerable GetPopupRoots(IVisual root) + { + foreach (var control in root.GetVisualDescendants().OfType()) + { + if (control is Popup { Host: PopupRoot r0 }) + { + yield return r0; + } + + if (control.GetValue(ContextFlyoutProperty) is IPopupHostProvider { PopupHost: PopupRoot r1 }) + { + yield return r1; + } + + if (control.GetValue(FlyoutBase.AttachedFlyoutProperty) is IPopupHostProvider { PopupHost: PopupRoot r2 }) + { + yield return r2; + } + + if (control.GetValue(ToolTipDiagnostics.ToolTipProperty) is IPopupHostProvider { PopupHost: PopupRoot r3 }) + { + yield return r3; + } + + if (control.GetValue(ContextMenuProperty) is IPopupHostProvider { PopupHost: PopupRoot r4 }) + { + yield return r4; + } + } + } + private void RawKeyDown(RawKeyEventArgs e) { var vm = (MainViewModel?)DataContext; @@ -123,16 +156,13 @@ namespace Avalonia.Diagnostics.Views { IControl? control = null; - foreach (var popup in Root.GetVisualDescendants().OfType()) + foreach (var popupRoot in GetPopupRoots(Root)) { - if (popup.Host?.HostedVisualTreeRoot is PopupRoot popupRoot) - { - control = GetHoveredControl(popupRoot); + control = GetHoveredControl(popupRoot); - if (control != null) - { - break; - } + if (control != null) + { + break; } } From 838626d763a9e446844244636c3cc51d55cbd946 Mon Sep 17 00:00:00 2001 From: Luis von der Eltz Date: Fri, 16 Jul 2021 10:33:51 +0200 Subject: [PATCH 08/26] remove c#9 features, clean up --- .../Diagnostics/Views/MainWindow.xaml.cs | 38 +++++++++---------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs b/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs index 26e197d790..cfb9e2ead9 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs @@ -111,35 +111,33 @@ namespace Avalonia.Diagnostics.Views .FirstOrDefault(); } - private static IEnumerable GetPopupRoots(IVisual root) + private static List GetPopupRoots(IVisual root) { - foreach (var control in root.GetVisualDescendants().OfType()) - { - if (control is Popup { Host: PopupRoot r0 }) - { - yield return r0; - } - - if (control.GetValue(ContextFlyoutProperty) is IPopupHostProvider { PopupHost: PopupRoot r1 }) - { - yield return r1; - } + var popupRoots = new List(); - if (control.GetValue(FlyoutBase.AttachedFlyoutProperty) is IPopupHostProvider { PopupHost: PopupRoot r2 }) + void ProcessProperty(IControl control, AvaloniaProperty property) + { + if (control.GetValue(property) is IPopupHostProvider popupProvider + && popupProvider.PopupHost is PopupRoot popupRoot) { - yield return r2; + popupRoots.Add(popupRoot); } + } - if (control.GetValue(ToolTipDiagnostics.ToolTipProperty) is IPopupHostProvider { PopupHost: PopupRoot r3 }) + foreach (var control in root.GetVisualDescendants().OfType()) + { + if (control is Popup p && p.Host is PopupRoot popupRoot) { - yield return r3; + popupRoots.Add(popupRoot); } - if (control.GetValue(ContextMenuProperty) is IPopupHostProvider { PopupHost: PopupRoot r4 }) - { - yield return r4; - } + ProcessProperty(control, ContextFlyoutProperty); + ProcessProperty(control, ContextMenuProperty); + ProcessProperty(control, FlyoutBase.AttachedFlyoutProperty); + ProcessProperty(control, ToolTipDiagnostics.ToolTipProperty); } + + return popupRoots; } private void RawKeyDown(RawKeyEventArgs e) From 2387e0bb5af5fa7448847bf11fd5157a0f111fcd Mon Sep 17 00:00:00 2001 From: Luis von der Eltz Date: Wed, 21 Jul 2021 18:34:14 +0200 Subject: [PATCH 09/26] Add option to freez popups (Alt + Ctrl + F) --- .../Diagnostics/ViewModels/MainViewModel.cs | 7 +++++++ .../Diagnostics/Views/MainWindow.xaml.cs | 17 +++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs index 07ae222a9c..d0a4ad38c5 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs @@ -21,6 +21,7 @@ namespace Avalonia.Diagnostics.ViewModels private bool _shouldVisualizeMarginPadding = true; private bool _shouldVisualizeDirtyRects; private bool _showFpsOverlay; + private bool _freezePopups; #nullable disable // Remove "nullable disable" after MemberNotNull will work on our CI. @@ -40,6 +41,12 @@ namespace Avalonia.Diagnostics.ViewModels Console = new ConsoleViewModel(UpdateConsoleContext); } + public bool FreezePopups + { + get => _freezePopups; + set => RaiseAndSetIfChanged(ref _freezePopups, value); + } + public bool ShouldVisualizeMarginPadding { get => _shouldVisualizeMarginPadding; diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs b/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs index cfb9e2ead9..810a630f46 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Reactive.Linq; +using System.Reactive.Subjects; using Avalonia.Controls; using Avalonia.Controls.Diagnostics; using Avalonia.Controls.Primitives; @@ -173,6 +174,22 @@ namespace Avalonia.Diagnostics.Views break; } + + case RawInputModifiers.Control | RawInputModifiers.Alt when e.Key == Key.F: + { + vm.FreezePopups = !vm.FreezePopups; + + foreach (var popupRoot in GetPopupRoots(Root)) + { + if (popupRoot.Parent is Popup popup) + { + popup.IsLightDismissEnabled = !vm.FreezePopups; + } + } + + break; + } + case RawInputModifiers.Alt when e.Key == Key.S || e.Key == Key.D: { vm.EnableSnapshotStyles(e.Key == Key.S); From df2079454079e43a59ca3b8032ac5837a8cf8fb6 Mon Sep 17 00:00:00 2001 From: Luis von der Eltz Date: Thu, 22 Jul 2021 12:01:20 +0200 Subject: [PATCH 10/26] Set LightDimissEnabled via SetValue() --- .../Diagnostics/Views/MainWindow.xaml.cs | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs b/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs index 810a630f46..1791672940 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs @@ -1,15 +1,18 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reactive.Disposables; using System.Reactive.Linq; using System.Reactive.Subjects; using Avalonia.Controls; using Avalonia.Controls.Diagnostics; using Avalonia.Controls.Primitives; +using Avalonia.Data; using Avalonia.Diagnostics.ViewModels; using Avalonia.Input; using Avalonia.Input.Raw; using Avalonia.Markup.Xaml; +using Avalonia.Media; using Avalonia.Styling; using Avalonia.VisualTree; @@ -18,6 +21,7 @@ namespace Avalonia.Diagnostics.Views internal class MainWindow : Window, IStyleHost { private readonly IDisposable _keySubscription; + private readonly Dictionary _frozenPopupStates; private TopLevel? _root; public MainWindow() @@ -28,6 +32,8 @@ namespace Avalonia.Diagnostics.Views .OfType() .Subscribe(RawKeyDown); + _frozenPopupStates = new Dictionary(); + EventHandler? lh = default; lh = (s, e) => { @@ -183,7 +189,25 @@ namespace Avalonia.Diagnostics.Views { if (popupRoot.Parent is Popup popup) { - popup.IsLightDismissEnabled = !vm.FreezePopups; + if (vm.FreezePopups) + { + var lightDismissEnabledState = popup.SetValue( + Popup.IsLightDismissEnabledProperty, + !vm.FreezePopups, + BindingPriority.Animation); + + if (lightDismissEnabledState != null) + { + _frozenPopupStates[popup] = lightDismissEnabledState; + } + } + else + { + if (_frozenPopupStates.TryGetValue(popup, out var state)) + { + state.Dispose(); + } + } } } From cabe6daa3f6f13d0991655465f6d286029eb1e27 Mon Sep 17 00:00:00 2001 From: Luis von der Eltz Date: Fri, 23 Jul 2021 10:57:19 +0200 Subject: [PATCH 11/26] Review changes --- .../Diagnostics/Views/MainWindow.xaml.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs b/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs index 1791672940..a85fe6c0c4 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs @@ -86,6 +86,13 @@ namespace Avalonia.Diagnostics.Views base.OnClosed(e); _keySubscription.Dispose(); + foreach (var state in _frozenPopupStates) + { + state.Value.Dispose(); + } + + _frozenPopupStates.Clear(); + if (_root != null) { _root.Closed -= RootClosed; @@ -203,9 +210,11 @@ namespace Avalonia.Diagnostics.Views } else { - if (_frozenPopupStates.TryGetValue(popup, out var state)) + //TODO Use Dictionary.Remove(Key, out Value) in netstandard 2.1 + if (_frozenPopupStates.ContainsKey(popup)) { - state.Dispose(); + _frozenPopupStates[popup].Dispose(); + _frozenPopupStates.Remove(popup); } } } From 98a436481064952a4176f190820cacadcc47db16 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Sun, 1 Aug 2021 01:16:38 -0400 Subject: [PATCH 12/26] Handle horizontal wheel scrolling in DataGrid --- .../ControlCatalog/Pages/DataGridPage.xaml | 2 +- src/Avalonia.Controls.DataGrid/DataGrid.cs | 57 +++++++++++++++---- 2 files changed, 48 insertions(+), 11 deletions(-) diff --git a/samples/ControlCatalog/Pages/DataGridPage.xaml b/samples/ControlCatalog/Pages/DataGridPage.xaml index 820c1324e3..340b3376f5 100644 --- a/samples/ControlCatalog/Pages/DataGridPage.xaml +++ b/samples/ControlCatalog/Pages/DataGridPage.xaml @@ -28,7 +28,7 @@ DockPanel.Dock="Top"/> - + diff --git a/src/Avalonia.Controls.DataGrid/DataGrid.cs b/src/Avalonia.Controls.DataGrid/DataGrid.cs index 3887bb3380..63e6950ae8 100644 --- a/src/Avalonia.Controls.DataGrid/DataGrid.cs +++ b/src/Avalonia.Controls.DataGrid/DataGrid.cs @@ -25,6 +25,7 @@ using System.ComponentModel.DataAnnotations; using Avalonia.Controls.Utils; using Avalonia.Layout; using Avalonia.Controls.Metadata; +using Avalonia.Input.GestureRecognizers; namespace Avalonia.Controls { @@ -2214,35 +2215,71 @@ namespace Avalonia.Controls /// PointerWheelEventArgs protected override void OnPointerWheelChanged(PointerWheelEventArgs e) { - if (IsEnabled && !e.Handled && DisplayData.NumDisplayedScrollingElements > 0) + e.Handled = e.Handled || UpdateScroll(e.Delta * DATAGRID_mouseWheelDelta); + } + + internal bool UpdateScroll(Vector delta) + { + if (IsEnabled && DisplayData.NumDisplayedScrollingElements > 0) { - double scrollHeight = 0; - var delta = DATAGRID_mouseWheelDelta * e.Delta.Y; - var deltaAbs = Math.Abs(delta); + var handled = false; + var scrollHeight = 0d; - if (delta > 0) + // Vertical scroll handling + if (delta.Y > 0) { - scrollHeight = Math.Max(-_verticalOffset, -deltaAbs); + scrollHeight = Math.Max(-_verticalOffset, -delta.Y); } - else if (delta < 0) + else if (delta.Y < 0) { if (_vScrollBar != null && VerticalScrollBarVisibility == ScrollBarVisibility.Visible) { - scrollHeight = Math.Min(Math.Max(0, _vScrollBar.Maximum - _verticalOffset), deltaAbs); + scrollHeight = Math.Min(Math.Max(0, _vScrollBar.Maximum - _verticalOffset), -delta.Y); } else { double maximum = EdgedRowsHeightCalculated - CellsHeight; - scrollHeight = Math.Min(Math.Max(0, maximum - _verticalOffset), deltaAbs); + scrollHeight = Math.Min(Math.Max(0, maximum - _verticalOffset), -delta.Y); } } + if (scrollHeight != 0) { DisplayData.PendingVerticalScrollHeight = scrollHeight; + handled = true; + } + + // Horizontal scroll handling + if (delta.X != 0) + { + var originalHorizontalOffset = HorizontalOffset; + var horizontalOffset = originalHorizontalOffset - delta.X; + var widthNotVisible = Math.Max(0, ColumnsInternal.VisibleEdgedColumnsWidth - CellsWidth); + + if (horizontalOffset < 0) + { + horizontalOffset = 0; + } + if (horizontalOffset > widthNotVisible) + { + horizontalOffset = widthNotVisible; + } + + if (horizontalOffset != originalHorizontalOffset) + { + HorizontalOffset = horizontalOffset; + handled = true; + } + } + + if (handled) + { InvalidateRowsMeasure(invalidateIndividualElements: false); - e.Handled = true; + return true; } } + + return false; } /// From 7e3b6ecff5dc187c0b4a6c535673556ad8d1b168 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Sun, 1 Aug 2021 01:16:55 -0400 Subject: [PATCH 13/26] Handle touch scrolling in DataGrid --- src/Avalonia.Controls.DataGrid/DataGridCell.cs | 2 +- .../Primitives/DataGridRowsPresenter.cs | 13 +++++++++++++ src/Avalonia.Controls.DataGrid/Themes/Default.xaml | 6 +++++- src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml | 6 +++++- 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/Avalonia.Controls.DataGrid/DataGridCell.cs b/src/Avalonia.Controls.DataGrid/DataGridCell.cs index 445dc541a7..47bf7b906c 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridCell.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridCell.cs @@ -173,7 +173,7 @@ namespace Avalonia.Controls } if (OwningRow != null) { - e.Handled = OwningGrid.UpdateStateOnMouseLeftButtonDown(e, ColumnIndex, OwningRow.Slot, !e.Handled); + OwningGrid.UpdateStateOnMouseLeftButtonDown(e, ColumnIndex, OwningRow.Slot, !e.Handled); OwningGrid.UpdatedStateOnMouseLeftButtonDown = true; } } diff --git a/src/Avalonia.Controls.DataGrid/Primitives/DataGridRowsPresenter.cs b/src/Avalonia.Controls.DataGrid/Primitives/DataGridRowsPresenter.cs index 0d19f4c479..308ebc69d4 100644 --- a/src/Avalonia.Controls.DataGrid/Primitives/DataGridRowsPresenter.cs +++ b/src/Avalonia.Controls.DataGrid/Primitives/DataGridRowsPresenter.cs @@ -5,6 +5,9 @@ using System; using System.Diagnostics; + +using Avalonia.Input; +using Avalonia.Input.GestureRecognizers; using Avalonia.Layout; using Avalonia.Media; @@ -16,6 +19,11 @@ namespace Avalonia.Controls.Primitives /// public sealed class DataGridRowsPresenter : Panel { + public DataGridRowsPresenter() + { + AddHandler(Gestures.ScrollGestureEvent, OnScrollGesture); + } + internal DataGrid OwningGrid { get; @@ -176,6 +184,11 @@ namespace Avalonia.Controls.Primitives return new Size(totalCellsWidth + headerWidth, totalHeight); } + private void OnScrollGesture(object sender, ScrollGestureEventArgs e) + { + e.Handled = e.Handled || OwningGrid.UpdateScroll(-e.Delta); + } + #if DEBUG internal void PrintChildren() { diff --git a/src/Avalonia.Controls.DataGrid/Themes/Default.xaml b/src/Avalonia.Controls.DataGrid/Themes/Default.xaml index 09d19c8e43..ca0873e183 100644 --- a/src/Avalonia.Controls.DataGrid/Themes/Default.xaml +++ b/src/Avalonia.Controls.DataGrid/Themes/Default.xaml @@ -247,7 +247,11 @@ - + + + + + diff --git a/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml b/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml index f2dbf42196..8ccf717d94 100644 --- a/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml +++ b/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml @@ -601,7 +601,11 @@ + Grid.ColumnSpan="3"> + + + + Date: Sun, 1 Aug 2021 02:57:57 -0400 Subject: [PATCH 14/26] Handle DataGridCell_PointerPressed if not touch --- src/Avalonia.Controls.DataGrid/DataGridCell.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls.DataGrid/DataGridCell.cs b/src/Avalonia.Controls.DataGrid/DataGridCell.cs index 241d543ec3..7dda936317 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridCell.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridCell.cs @@ -173,7 +173,15 @@ namespace Avalonia.Controls } if (OwningRow != null) { - OwningGrid.UpdateStateOnMouseLeftButtonDown(e, ColumnIndex, OwningRow.Slot, !e.Handled); + var handled = OwningGrid.UpdateStateOnMouseLeftButtonDown(e, ColumnIndex, OwningRow.Slot, !e.Handled); + + // Do not handle PointerPressed with touch, + // so we can start scroll gesture on the same event. + if (e.Pointer.Type != PointerType.Touch) + { + e.Handled = handled; + } + OwningGrid.UpdatedStateOnMouseLeftButtonDown = true; } } From 64922a34a937757380700199fcb555f8f39f6e90 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Sun, 1 Aug 2021 21:45:07 -0400 Subject: [PATCH 15/26] Add CornerRadius to TemplatedControl and use it where possible --- samples/ControlCatalog/SideBar.xaml | 1 - samples/RenderDemo/SideBar.xaml | 1 - .../Flyouts/FlyoutPresenter.cs | 9 ----- .../Primitives/TemplatedControl.cs | 40 ++++++++++++++----- .../AutoCompleteBox.xaml | 1 + src/Avalonia.Themes.Default/Button.xaml | 3 +- .../ButtonSpinner.xaml | 2 + src/Avalonia.Themes.Default/Calendar.xaml | 3 +- .../CalendarDatePicker.xaml | 3 +- src/Avalonia.Themes.Default/CalendarItem.xaml | 5 ++- src/Avalonia.Themes.Default/Carousel.xaml | 3 +- src/Avalonia.Themes.Default/CheckBox.xaml | 1 + src/Avalonia.Themes.Default/ComboBox.xaml | 3 +- src/Avalonia.Themes.Default/ComboBoxItem.xaml | 1 + .../ContentControl.xaml | 3 +- src/Avalonia.Themes.Default/ContextMenu.xaml | 1 + .../DataValidationErrors.xaml | 1 + src/Avalonia.Themes.Default/DatePicker.xaml | 3 ++ src/Avalonia.Themes.Default/Expander.xaml | 5 ++- src/Avalonia.Themes.Default/GridSplitter.xaml | 1 + src/Avalonia.Themes.Default/ItemsControl.xaml | 1 + src/Avalonia.Themes.Default/Label.xaml | 1 + src/Avalonia.Themes.Default/ListBox.xaml | 3 +- src/Avalonia.Themes.Default/ListBoxItem.xaml | 1 + src/Avalonia.Themes.Default/Menu.xaml | 3 +- src/Avalonia.Themes.Default/MenuItem.xaml | 6 ++- .../NotificationCard.xaml | 1 + .../NumericUpDown.xaml | 2 +- src/Avalonia.Themes.Default/ProgressBar.xaml | 2 +- src/Avalonia.Themes.Default/RepeatButton.xaml | 1 + src/Avalonia.Themes.Default/Separator.xaml | 1 + src/Avalonia.Themes.Default/TabControl.xaml | 2 +- src/Avalonia.Themes.Default/TabItem.xaml | 2 +- src/Avalonia.Themes.Default/TabStripItem.xaml | 3 +- src/Avalonia.Themes.Default/TextBox.xaml | 3 +- src/Avalonia.Themes.Default/TimePicker.xaml | 3 ++ src/Avalonia.Themes.Default/ToggleButton.xaml | 3 +- src/Avalonia.Themes.Default/ToolTip.xaml | 3 +- src/Avalonia.Themes.Default/TreeView.xaml | 3 +- src/Avalonia.Themes.Default/TreeViewItem.xaml | 1 + src/Avalonia.Themes.Default/UserControl.xaml | 1 + .../Controls/AutoCompleteBox.xaml | 4 +- .../Controls/Button.xaml | 6 +-- .../Controls/ButtonSpinner.xaml | 3 +- .../Controls/Calendar.xaml | 10 ++++- .../Controls/CalendarDatePicker.xaml | 2 + .../Controls/CalendarItem.xaml | 8 +++- .../Controls/Carousel.xaml | 3 +- .../Controls/CheckBox.xaml | 13 ++---- .../Controls/ComboBox.xaml | 13 ++---- .../Controls/ComboBoxItem.xaml | 1 + .../Controls/ContentControl.xaml | 3 +- .../Controls/ContextMenu.xaml | 3 +- .../Controls/DataValidationErrors.xaml | 2 + .../Controls/DatePicker.xaml | 16 ++++++-- .../Controls/Expander.xaml | 29 +++++++------- .../Controls/GridSplitter.xaml | 1 + .../Controls/ItemsControl.xaml | 1 + .../Controls/Label.xaml | 3 +- .../Controls/ListBox.xaml | 8 ++-- .../Controls/ListBoxItem.xaml | 1 + src/Avalonia.Themes.Fluent/Controls/Menu.xaml | 1 + .../Controls/MenuItem.xaml | 6 ++- .../Controls/NotificationCard.xaml | 6 ++- .../Controls/NumericUpDown.xaml | 2 + .../Controls/ProgressBar.xaml | 3 +- .../Controls/RadioButton.xaml | 11 ++--- .../Controls/RepeatButton.xaml | 2 + .../Controls/Separator.xaml | 1 + .../Controls/Slider.xaml | 4 +- .../Controls/TabControl.xaml | 4 +- .../Controls/TabItem.xaml | 1 + .../Controls/TabStrip.xaml | 14 +++++-- .../Controls/TabStripItem.xaml | 1 + .../Controls/TextBox.xaml | 6 +-- .../Controls/TimePicker.xaml | 9 +++-- .../Controls/ToggleButton.xaml | 2 + .../Controls/ToolTip.xaml | 3 +- .../Controls/TreeView.xaml | 3 +- .../Controls/TreeViewItem.xaml | 1 + .../Controls/UserControl.xaml | 1 + 81 files changed, 223 insertions(+), 124 deletions(-) diff --git a/samples/ControlCatalog/SideBar.xaml b/samples/ControlCatalog/SideBar.xaml index 7c911e91e9..2b5215a3fe 100644 --- a/samples/ControlCatalog/SideBar.xaml +++ b/samples/ControlCatalog/SideBar.xaml @@ -16,7 +16,6 @@ diff --git a/samples/RenderDemo/SideBar.xaml b/samples/RenderDemo/SideBar.xaml index fd23067f61..b82a7b0514 100644 --- a/samples/RenderDemo/SideBar.xaml +++ b/samples/RenderDemo/SideBar.xaml @@ -7,7 +7,6 @@ diff --git a/src/Avalonia.Controls/Flyouts/FlyoutPresenter.cs b/src/Avalonia.Controls/Flyouts/FlyoutPresenter.cs index 10f97794d7..0f257224dd 100644 --- a/src/Avalonia.Controls/Flyouts/FlyoutPresenter.cs +++ b/src/Avalonia.Controls/Flyouts/FlyoutPresenter.cs @@ -6,15 +6,6 @@ namespace Avalonia.Controls { public class FlyoutPresenter : ContentControl { - public static readonly StyledProperty CornerRadiusProperty = - Border.CornerRadiusProperty.AddOwner(); - - public CornerRadius CornerRadius - { - get => GetValue(CornerRadiusProperty); - set => SetValue(CornerRadiusProperty, value); - } - protected override void OnKeyDown(KeyEventArgs e) { if (e.Key == Key.Escape) diff --git a/src/Avalonia.Controls/Primitives/TemplatedControl.cs b/src/Avalonia.Controls/Primitives/TemplatedControl.cs index 9c73ff2411..59975b072d 100644 --- a/src/Avalonia.Controls/Primitives/TemplatedControl.cs +++ b/src/Avalonia.Controls/Primitives/TemplatedControl.cs @@ -5,7 +5,8 @@ using Avalonia.Logging; using Avalonia.LogicalTree; using Avalonia.Media; using Avalonia.Styling; -using Avalonia.VisualTree; + +#nullable enable namespace Avalonia.Controls.Primitives { @@ -17,13 +18,13 @@ namespace Avalonia.Controls.Primitives /// /// Defines the property. /// - public static readonly StyledProperty BackgroundProperty = + public static readonly StyledProperty BackgroundProperty = Border.BackgroundProperty.AddOwner(); /// /// Defines the property. /// - public static readonly StyledProperty BorderBrushProperty = + public static readonly StyledProperty BorderBrushProperty = Border.BorderBrushProperty.AddOwner(); /// @@ -32,6 +33,12 @@ namespace Avalonia.Controls.Primitives public static readonly StyledProperty BorderThicknessProperty = Border.BorderThicknessProperty.AddOwner(); + /// + /// Defines the property. + /// + public static readonly StyledProperty CornerRadiusProperty = + Border.CornerRadiusProperty.AddOwner(); + /// /// Defines the property. /// @@ -59,7 +66,7 @@ namespace Avalonia.Controls.Primitives /// /// Defines the property. /// - public static readonly StyledProperty ForegroundProperty = + public static readonly StyledProperty ForegroundProperty = TextBlock.ForegroundProperty.AddOwner(); /// @@ -71,8 +78,8 @@ namespace Avalonia.Controls.Primitives /// /// Defines the property. /// - public static readonly StyledProperty TemplateProperty = - AvaloniaProperty.Register(nameof(Template)); + public static readonly StyledProperty TemplateProperty = + AvaloniaProperty.Register(nameof(Template)); /// /// Defines the IsTemplateFocusTarget attached property. @@ -88,7 +95,7 @@ namespace Avalonia.Controls.Primitives "TemplateApplied", RoutingStrategies.Direct); - private IControlTemplate _appliedTemplate; + private IControlTemplate? _appliedTemplate; /// /// Initializes static members of the class. @@ -111,7 +118,7 @@ namespace Avalonia.Controls.Primitives /// /// Gets or sets the brush used to draw the control's background. /// - public IBrush Background + public IBrush? Background { get { return GetValue(BackgroundProperty); } set { SetValue(BackgroundProperty, value); } @@ -120,7 +127,7 @@ namespace Avalonia.Controls.Primitives /// /// Gets or sets the brush used to draw the control's border. /// - public IBrush BorderBrush + public IBrush? BorderBrush { get { return GetValue(BorderBrushProperty); } set { SetValue(BorderBrushProperty, value); } @@ -135,6 +142,15 @@ namespace Avalonia.Controls.Primitives set { SetValue(BorderThicknessProperty, value); } } + /// + /// Gets or sets the radius of the border rounded corners. + /// + public CornerRadius CornerRadius + { + get { return GetValue(CornerRadiusProperty); } + set { SetValue(CornerRadiusProperty, value); } + } + /// /// Gets or sets the font family used to draw the control's text. /// @@ -174,7 +190,7 @@ namespace Avalonia.Controls.Primitives /// /// Gets or sets the brush used to draw the control's text and other foreground elements. /// - public IBrush Foreground + public IBrush? Foreground { get { return GetValue(ForegroundProperty); } set { SetValue(ForegroundProperty, value); } @@ -192,7 +208,7 @@ namespace Avalonia.Controls.Primitives /// /// Gets or sets the template that defines the control's appearance. /// - public IControlTemplate Template + public IControlTemplate? Template { get { return GetValue(TemplateProperty); } set { SetValue(TemplateProperty, value); } @@ -265,7 +281,9 @@ namespace Avalonia.Controls.Primitives var e = new TemplateAppliedEventArgs(nameScope); OnApplyTemplate(e); +#pragma warning disable CS0618 // Type or member is obsolete OnTemplateApplied(e); +#pragma warning restore CS0618 // Type or member is obsolete RaiseEvent(e); } diff --git a/src/Avalonia.Themes.Default/AutoCompleteBox.xaml b/src/Avalonia.Themes.Default/AutoCompleteBox.xaml index 66d0f17ede..fe4cd48e72 100644 --- a/src/Avalonia.Themes.Default/AutoCompleteBox.xaml +++ b/src/Avalonia.Themes.Default/AutoCompleteBox.xaml @@ -11,6 +11,7 @@ Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="{TemplateBinding CornerRadius}" Padding="{TemplateBinding Padding}" Watermark="{TemplateBinding Watermark}" DataValidationErrors.Errors="{TemplateBinding (DataValidationErrors.Errors)}" /> diff --git a/src/Avalonia.Themes.Default/Button.xaml b/src/Avalonia.Themes.Default/Button.xaml index 698ddec2a8..81d96aaa14 100644 --- a/src/Avalonia.Themes.Default/Button.xaml +++ b/src/Avalonia.Themes.Default/Button.xaml @@ -13,6 +13,7 @@ Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="{TemplateBinding CornerRadius}" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Padding="{TemplateBinding Padding}" @@ -31,4 +32,4 @@ - \ No newline at end of file + diff --git a/src/Avalonia.Themes.Default/ButtonSpinner.xaml b/src/Avalonia.Themes.Default/ButtonSpinner.xaml index 89fbb9d64d..ce2b85d2b5 100644 --- a/src/Avalonia.Themes.Default/ButtonSpinner.xaml +++ b/src/Avalonia.Themes.Default/ButtonSpinner.xaml @@ -47,6 +47,7 @@ Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="{TemplateBinding CornerRadius}" Margin="{TemplateBinding Padding}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}"> @@ -73,6 +74,7 @@ Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="{TemplateBinding CornerRadius}" Margin="{TemplateBinding Padding}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}"> diff --git a/src/Avalonia.Themes.Default/Calendar.xaml b/src/Avalonia.Themes.Default/Calendar.xaml index 6bbee4ef17..4b67aa232b 100644 --- a/src/Avalonia.Themes.Default/Calendar.xaml +++ b/src/Avalonia.Themes.Default/Calendar.xaml @@ -22,10 +22,11 @@ Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="{TemplateBinding CornerRadius}" HeaderBackground="{TemplateBinding HeaderBackground}"/> - \ No newline at end of file + diff --git a/src/Avalonia.Themes.Default/CalendarDatePicker.xaml b/src/Avalonia.Themes.Default/CalendarDatePicker.xaml index aab7d06c46..57b77f70ea 100644 --- a/src/Avalonia.Themes.Default/CalendarDatePicker.xaml +++ b/src/Avalonia.Themes.Default/CalendarDatePicker.xaml @@ -88,7 +88,8 @@ \ No newline at end of file + diff --git a/src/Avalonia.Themes.Default/ContextMenu.xaml b/src/Avalonia.Themes.Default/ContextMenu.xaml index 9b84253c8a..0df4866184 100644 --- a/src/Avalonia.Themes.Default/ContextMenu.xaml +++ b/src/Avalonia.Themes.Default/ContextMenu.xaml @@ -9,6 +9,7 @@ diff --git a/src/Avalonia.Themes.Default/DatePicker.xaml b/src/Avalonia.Themes.Default/DatePicker.xaml index da878c88e2..c6c117138d 100644 --- a/src/Avalonia.Themes.Default/DatePicker.xaml +++ b/src/Avalonia.Themes.Default/DatePicker.xaml @@ -134,6 +134,7 @@ Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="{TemplateBinding CornerRadius}" IsEnabled="{TemplateBinding IsEnabled}" MinWidth="{DynamicResource DatePickerThemeMinWidth}" MaxWidth="{DynamicResource DatePickerThemeMaxWidth}" @@ -148,6 +149,7 @@ BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="{TemplateBinding CornerRadius}" Content="{TemplateBinding Content}" TextBlock.Foreground="{TemplateBinding Foreground}" HorizontalContentAlignment="Stretch" @@ -242,6 +244,7 @@ diff --git a/src/Avalonia.Themes.Default/Expander.xaml b/src/Avalonia.Themes.Default/Expander.xaml index 08d8b4c995..5e0958c54c 100644 --- a/src/Avalonia.Themes.Default/Expander.xaml +++ b/src/Avalonia.Themes.Default/Expander.xaml @@ -10,7 +10,10 @@ \ No newline at end of file + diff --git a/src/Avalonia.Themes.Default/MenuItem.xaml b/src/Avalonia.Themes.Default/MenuItem.xaml index 4bfae4c223..18bf79ce6c 100644 --- a/src/Avalonia.Themes.Default/MenuItem.xaml +++ b/src/Avalonia.Themes.Default/MenuItem.xaml @@ -14,7 +14,8 @@ + BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="{TemplateBinding CornerRadius}"> @@ -96,7 +97,8 @@ + BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="{TemplateBinding CornerRadius}"> diff --git a/src/Avalonia.Themes.Default/NumericUpDown.xaml b/src/Avalonia.Themes.Default/NumericUpDown.xaml index 025e822404..6740be69bb 100644 --- a/src/Avalonia.Themes.Default/NumericUpDown.xaml +++ b/src/Avalonia.Themes.Default/NumericUpDown.xaml @@ -9,6 +9,7 @@ - + diff --git a/src/Avalonia.Themes.Default/RepeatButton.xaml b/src/Avalonia.Themes.Default/RepeatButton.xaml index 702e4e6ebd..a9a03c8ed5 100644 --- a/src/Avalonia.Themes.Default/RepeatButton.xaml +++ b/src/Avalonia.Themes.Default/RepeatButton.xaml @@ -20,6 +20,7 @@ Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="{TemplateBinding CornerRadius}" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Padding="{TemplateBinding Padding}" diff --git a/src/Avalonia.Themes.Default/Separator.xaml b/src/Avalonia.Themes.Default/Separator.xaml index cf0db16ee6..6a318d2e85 100644 --- a/src/Avalonia.Themes.Default/Separator.xaml +++ b/src/Avalonia.Themes.Default/Separator.xaml @@ -6,6 +6,7 @@ diff --git a/src/Avalonia.Themes.Default/TabControl.xaml b/src/Avalonia.Themes.Default/TabControl.xaml index ed2e67df28..afb5010baa 100644 --- a/src/Avalonia.Themes.Default/TabControl.xaml +++ b/src/Avalonia.Themes.Default/TabControl.xaml @@ -3,9 +3,9 @@ diff --git a/src/Avalonia.Themes.Default/TabItem.xaml b/src/Avalonia.Themes.Default/TabItem.xaml index 6e344ce58e..c7748299a0 100644 --- a/src/Avalonia.Themes.Default/TabItem.xaml +++ b/src/Avalonia.Themes.Default/TabItem.xaml @@ -12,11 +12,11 @@ Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="{TemplateBinding CornerRadius}" ContentTemplate="{TemplateBinding HeaderTemplate}" Content="{TemplateBinding Header}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" - Margin="{TemplateBinding Margin}" Padding="{TemplateBinding Padding}"/> diff --git a/src/Avalonia.Themes.Default/TabStripItem.xaml b/src/Avalonia.Themes.Default/TabStripItem.xaml index 28c4c68a3d..61eecc0395 100644 --- a/src/Avalonia.Themes.Default/TabStripItem.xaml +++ b/src/Avalonia.Themes.Default/TabStripItem.xaml @@ -9,6 +9,7 @@ Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="{TemplateBinding CornerRadius}" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" @@ -20,4 +21,4 @@ - \ No newline at end of file + diff --git a/src/Avalonia.Themes.Default/TextBox.xaml b/src/Avalonia.Themes.Default/TextBox.xaml index 12df4b6213..9471beaaeb 100644 --- a/src/Avalonia.Themes.Default/TextBox.xaml +++ b/src/Avalonia.Themes.Default/TextBox.xaml @@ -30,7 +30,8 @@ + BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="{TemplateBinding CornerRadius}"> diff --git a/src/Avalonia.Themes.Default/TimePicker.xaml b/src/Avalonia.Themes.Default/TimePicker.xaml index c76f900cfe..a58fd62a99 100644 --- a/src/Avalonia.Themes.Default/TimePicker.xaml +++ b/src/Avalonia.Themes.Default/TimePicker.xaml @@ -58,6 +58,7 @@ Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="{TemplateBinding CornerRadius}" IsEnabled="{TemplateBinding IsEnabled}" MinWidth="{DynamicResource TimePickerThemeMinWidth}" MaxWidth="{DynamicResource TimePickerThemeMaxWidth}" @@ -71,6 +72,7 @@ BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="{TemplateBinding CornerRadius}" Content="{TemplateBinding Content}" TextBlock.Foreground="{TemplateBinding Foreground}" HorizontalContentAlignment="Stretch" @@ -178,6 +180,7 @@ Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="{TemplateBinding CornerRadius}" Padding="{DynamicResource DateTimeFlyoutBorderPadding}" MaxHeight="398"> diff --git a/src/Avalonia.Themes.Default/ToggleButton.xaml b/src/Avalonia.Themes.Default/ToggleButton.xaml index 9e05c38eef..ffebd4f63d 100644 --- a/src/Avalonia.Themes.Default/ToggleButton.xaml +++ b/src/Avalonia.Themes.Default/ToggleButton.xaml @@ -13,6 +13,7 @@ Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="{TemplateBinding CornerRadius}" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Padding="{TemplateBinding Padding}" @@ -35,4 +36,4 @@ - \ No newline at end of file + diff --git a/src/Avalonia.Themes.Default/ToolTip.xaml b/src/Avalonia.Themes.Default/ToolTip.xaml index 1fc0202dd3..35c1dceb8d 100644 --- a/src/Avalonia.Themes.Default/ToolTip.xaml +++ b/src/Avalonia.Themes.Default/ToolTip.xaml @@ -9,9 +9,10 @@ Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="{TemplateBinding CornerRadius}" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Padding="{TemplateBinding Padding}"/> - \ No newline at end of file + diff --git a/src/Avalonia.Themes.Default/TreeView.xaml b/src/Avalonia.Themes.Default/TreeView.xaml index 026bed5899..990d5d0823 100644 --- a/src/Avalonia.Themes.Default/TreeView.xaml +++ b/src/Avalonia.Themes.Default/TreeView.xaml @@ -8,7 +8,8 @@ + BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="{TemplateBinding CornerRadius}"> - + + @@ -36,6 +37,7 @@ Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="{TemplateBinding CornerRadius}" FontSize="{TemplateBinding FontSize}" FontFamily="{TemplateBinding FontFamily}" FontWeight="{TemplateBinding FontWeight}" diff --git a/src/Avalonia.Themes.Fluent/Controls/Button.xaml b/src/Avalonia.Themes.Fluent/Controls/Button.xaml index 597f5d00ec..53d53ef127 100644 --- a/src/Avalonia.Themes.Fluent/Controls/Button.xaml +++ b/src/Avalonia.Themes.Fluent/Controls/Button.xaml @@ -16,6 +16,7 @@ + @@ -29,6 +30,7 @@ Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="{TemplateBinding CornerRadius}" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" Padding="{TemplateBinding Padding}" @@ -93,8 +95,4 @@ - - diff --git a/src/Avalonia.Themes.Fluent/Controls/ButtonSpinner.xaml b/src/Avalonia.Themes.Fluent/Controls/ButtonSpinner.xaml index 12b4845522..d228c37912 100644 --- a/src/Avalonia.Themes.Fluent/Controls/ButtonSpinner.xaml +++ b/src/Avalonia.Themes.Fluent/Controls/ButtonSpinner.xaml @@ -58,6 +58,7 @@ + @@ -69,7 +70,7 @@ - + + + + + + - - - - - - - - \ No newline at end of file + diff --git a/src/Avalonia.Themes.Fluent/Controls/ContextMenu.xaml b/src/Avalonia.Themes.Fluent/Controls/ContextMenu.xaml index 5110d70a80..df800b4a06 100644 --- a/src/Avalonia.Themes.Fluent/Controls/ContextMenu.xaml +++ b/src/Avalonia.Themes.Fluent/Controls/ContextMenu.xaml @@ -39,6 +39,7 @@ + @@ -55,7 +56,7 @@ MaxWidth="{TemplateBinding MaxWidth}" MinHeight="{TemplateBinding MinHeight}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" - CornerRadius="{DynamicResource OverlayCornerRadius}"> + CornerRadius="{TemplateBinding CornerRadius}"> @@ -88,6 +89,7 @@ Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="{TemplateBinding CornerRadius}" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" /> diff --git a/src/Avalonia.Themes.Fluent/Controls/DatePicker.xaml b/src/Avalonia.Themes.Fluent/Controls/DatePicker.xaml index 032fdd9ae4..3e4471cada 100644 --- a/src/Avalonia.Themes.Fluent/Controls/DatePicker.xaml +++ b/src/Avalonia.Themes.Fluent/Controls/DatePicker.xaml @@ -8,6 +8,12 @@ + + + + + + 0,0,0,4 40 @@ -50,6 +56,7 @@ + diff --git a/src/Avalonia.Themes.Fluent/Controls/Expander.xaml b/src/Avalonia.Themes.Fluent/Controls/Expander.xaml index 3f70939953..d5d44e1270 100644 --- a/src/Avalonia.Themes.Fluent/Controls/Expander.xaml +++ b/src/Avalonia.Themes.Fluent/Controls/Expander.xaml @@ -1,23 +1,23 @@ - - + + Expanded content - + Expanded content - + Expanded content - + Expanded content @@ -51,6 +51,7 @@ + @@ -140,31 +141,31 @@ - - - - - diff --git a/src/Avalonia.Themes.Fluent/Controls/TimePicker.xaml b/src/Avalonia.Themes.Fluent/Controls/TimePicker.xaml index 1c52c6272c..3320fc9a41 100644 --- a/src/Avalonia.Themes.Fluent/Controls/TimePicker.xaml +++ b/src/Avalonia.Themes.Fluent/Controls/TimePicker.xaml @@ -37,6 +37,7 @@ + @@ -59,6 +60,7 @@ Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="{TemplateBinding CornerRadius}" IsEnabled="{TemplateBinding IsEnabled}" MinWidth="{DynamicResource TimePickerThemeMinWidth}" MaxWidth="{DynamicResource TimePickerThemeMaxWidth}" @@ -72,11 +74,11 @@ BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="{TemplateBinding CornerRadius}" Content="{TemplateBinding Content}" TextBlock.Foreground="{TemplateBinding Foreground}" HorizontalContentAlignment="Stretch" - VerticalContentAlignment="Stretch" - CornerRadius="{DynamicResource ControlCornerRadius}" /> + VerticalContentAlignment="Stretch" /> @@ -176,13 +178,14 @@ + diff --git a/src/Avalonia.Themes.Fluent/Controls/ToggleButton.xaml b/src/Avalonia.Themes.Fluent/Controls/ToggleButton.xaml index dd8e51e4e5..b1d07059b8 100644 --- a/src/Avalonia.Themes.Fluent/Controls/ToggleButton.xaml +++ b/src/Avalonia.Themes.Fluent/Controls/ToggleButton.xaml @@ -18,6 +18,7 @@ + @@ -29,6 +30,7 @@ Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="{TemplateBinding CornerRadius}" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" Padding="{TemplateBinding Padding}" diff --git a/src/Avalonia.Themes.Fluent/Controls/ToolTip.xaml b/src/Avalonia.Themes.Fluent/Controls/ToolTip.xaml index f7a1ebbc6b..debdfb2772 100644 --- a/src/Avalonia.Themes.Fluent/Controls/ToolTip.xaml +++ b/src/Avalonia.Themes.Fluent/Controls/ToolTip.xaml @@ -49,6 +49,7 @@ + @@ -61,7 +62,7 @@ Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" Padding="{TemplateBinding Padding}" - CornerRadius="{DynamicResource OverlayCornerRadius}"> + CornerRadius="{TemplateBinding CornerRadius}"> + BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="{TemplateBinding CornerRadius}"> Date: Wed, 4 Aug 2021 15:01:14 +0200 Subject: [PATCH 16/26] Make event actually keydown --- src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs b/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs index a85fe6c0c4..ea06c33e4d 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs @@ -1,9 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Reactive.Disposables; using System.Reactive.Linq; -using System.Reactive.Subjects; using Avalonia.Controls; using Avalonia.Controls.Diagnostics; using Avalonia.Controls.Primitives; @@ -12,7 +10,6 @@ using Avalonia.Diagnostics.ViewModels; using Avalonia.Input; using Avalonia.Input.Raw; using Avalonia.Markup.Xaml; -using Avalonia.Media; using Avalonia.Styling; using Avalonia.VisualTree; @@ -30,6 +27,7 @@ namespace Avalonia.Diagnostics.Views _keySubscription = InputManager.Instance.Process .OfType() + .Where(x => x.Type == RawKeyEventType.KeyDown) .Subscribe(RawKeyDown); _frozenPopupStates = new Dictionary(); From 5fb8126d2dfbb55ed62772a718f1610276794961 Mon Sep 17 00:00:00 2001 From: Luis von der Eltz Date: Wed, 4 Aug 2021 15:41:31 +0200 Subject: [PATCH 17/26] Add label for frozen popups to status bar --- .../Diagnostics/Views/MainView.xaml | 56 +++++++++++-------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/MainView.xaml b/src/Avalonia.Diagnostics/Diagnostics/Views/MainView.xaml index 8c4db33f91..6f2ac96a66 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Views/MainView.xaml +++ b/src/Avalonia.Diagnostics/Diagnostics/Views/MainView.xaml @@ -5,14 +5,14 @@ - + + IsEnabled="False" /> @@ -21,58 +21,68 @@ + IsEnabled="False" /> + IsEnabled="False" /> - + + IsEnabled="False" /> - + - - - + + + + Content="{Binding Content}" /> - + IsVisible="False" /> + + IsVisible="{Binding IsVisible}" /> + - - Hold Ctrl+Shift over a control to inspect. - - Focused: - - - Pointer Over: - - + + + Hold Ctrl+Shift over a control to inspect. + + Focused: + + + Pointer Over: + + + + + + From dc404b545e534ea904911ca9647f312f77e7ed6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Fri, 6 Aug 2021 08:49:05 +0200 Subject: [PATCH 18/26] Fix skia OpacityMask push and pop methods --- src/Skia/Avalonia.Skia/DrawingContextImpl.cs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index 2352b8b076..ea4c35d6e7 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -534,7 +534,11 @@ namespace Avalonia.Skia public void PushOpacityMask(IBrush mask, Rect bounds) { // TODO: This should be disposed - var paint = new SKPaint(); + var paint = new SKPaint() + { + IsAntialias = true, + Style = SKPaintStyle.StrokeAndFill + }; Canvas.SaveLayer(paint); _maskStack.Push(CreatePaint(paint, mask, bounds, true)); @@ -543,7 +547,14 @@ namespace Avalonia.Skia /// public void PopOpacityMask() { - using (var paint = new SKPaint { BlendMode = SKBlendMode.DstIn }) + using (var paint = new SKPaint + { + IsAntialias = true, + Style = SKPaintStyle.StrokeAndFill, + BlendMode = SKBlendMode.DstIn, + Color = new SKColor(0, 0, 0, 255), + ColorFilter = SKColorFilter.CreateLumaColor() + }) { Canvas.SaveLayer(paint); using (var paintWrapper = _maskStack.Pop()) From ae222e25e6b27b0035421d2583c2b37a4036fff1 Mon Sep 17 00:00:00 2001 From: Luis von der Eltz Date: Tue, 10 Aug 2021 11:30:19 +0200 Subject: [PATCH 19/26] Mark IVisualTreeHost [Obsolete] --- src/Avalonia.Visuals/VisualTree/IVisualTreeHost.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Avalonia.Visuals/VisualTree/IVisualTreeHost.cs b/src/Avalonia.Visuals/VisualTree/IVisualTreeHost.cs index b63c49bd5a..01212b238d 100644 --- a/src/Avalonia.Visuals/VisualTree/IVisualTreeHost.cs +++ b/src/Avalonia.Visuals/VisualTree/IVisualTreeHost.cs @@ -1,8 +1,11 @@ +using System; + namespace Avalonia.VisualTree { /// /// Interface for controls that host their own separate visual tree, such as popups. /// + [Obsolete] public interface IVisualTreeHost { /// From d666a4263c580b21c7221a972ee34aab65c86c6a Mon Sep 17 00:00:00 2001 From: "Luis v.d.Eltz" Date: Tue, 10 Aug 2021 11:30:42 +0200 Subject: [PATCH 20/26] Update comment Co-authored-by: Steven Kirk --- src/Avalonia.Controls/Diagnostics/ToolTipDiagnostics.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/Diagnostics/ToolTipDiagnostics.cs b/src/Avalonia.Controls/Diagnostics/ToolTipDiagnostics.cs index 58174b1039..4dfe5eb174 100644 --- a/src/Avalonia.Controls/Diagnostics/ToolTipDiagnostics.cs +++ b/src/Avalonia.Controls/Diagnostics/ToolTipDiagnostics.cs @@ -3,7 +3,7 @@ namespace Avalonia.Controls.Diagnostics { /// - /// Helper class to provide some diagnostics insides into . + /// Helper class to provide diagnostics information for . /// public static class ToolTipDiagnostics { From 08849539a72ccb7163bee028fd70fea20aa13b67 Mon Sep 17 00:00:00 2001 From: "Luis v.d.Eltz" Date: Tue, 10 Aug 2021 11:31:39 +0200 Subject: [PATCH 21/26] Update comment Co-authored-by: Steven Kirk --- src/Avalonia.Controls/Diagnostics/ToolTipDiagnostics.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Avalonia.Controls/Diagnostics/ToolTipDiagnostics.cs b/src/Avalonia.Controls/Diagnostics/ToolTipDiagnostics.cs index 4dfe5eb174..4acf2a217f 100644 --- a/src/Avalonia.Controls/Diagnostics/ToolTipDiagnostics.cs +++ b/src/Avalonia.Controls/Diagnostics/ToolTipDiagnostics.cs @@ -7,6 +7,9 @@ namespace Avalonia.Controls.Diagnostics /// public static class ToolTipDiagnostics { + /// + /// Provides access to the internal for use in DevTools. + /// public static AvaloniaProperty ToolTipProperty = ToolTip.ToolTipProperty; } } From 71ac5e3db8990c3b5a10bdf809dad8d68ceca4e9 Mon Sep 17 00:00:00 2001 From: Luis von der Eltz Date: Tue, 10 Aug 2021 11:41:05 +0200 Subject: [PATCH 22/26] Only IPopupHost should be root visual --- src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs index 4b957c2382..94707ac189 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs @@ -54,8 +54,7 @@ namespace Avalonia.Diagnostics.ViewModels } } - private bool IsRoot => Visual is TopLevel || - Visual is Popup || + private bool IsRoot => Visual is TopLevel || Visual is ContextMenu || Visual is IPopupHost; From 346015d804e777a1ea2f32f2252841a9135845ae Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 11 Aug 2021 21:03:52 +0200 Subject: [PATCH 23/26] Call WindowStateChanged when setting WindowState via code. Fixes #6399 --- native/Avalonia.Native/src/OSX/window.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/native/Avalonia.Native/src/OSX/window.mm b/native/Avalonia.Native/src/OSX/window.mm index 9c6a0e6187..0a78558d27 100644 --- a/native/Avalonia.Native/src/OSX/window.mm +++ b/native/Avalonia.Native/src/OSX/window.mm @@ -1204,6 +1204,7 @@ private: } _actualWindowState = _lastWindowState; + WindowEvents->WindowStateChanged(_actualWindowState); } From 24c8af1b626dbc2376cd67006f847b8464ef40b4 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 11 Aug 2021 21:04:37 +0200 Subject: [PATCH 24/26] Manually restore parent windows before showing child. --- native/Avalonia.Native/src/OSX/window.mm | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/native/Avalonia.Native/src/OSX/window.mm b/native/Avalonia.Native/src/OSX/window.mm index 0a78558d27..14fe60ab0b 100644 --- a/native/Avalonia.Native/src/OSX/window.mm +++ b/native/Avalonia.Native/src/OSX/window.mm @@ -713,6 +713,12 @@ private: if(cparent == nullptr) return E_INVALIDARG; + // If one tries to show a child window with a minimized parent window, then the parent window will be + // restored but MacOS isn't kind enough to *tell* us that, so the window will be left in a non-interactive + // state. Detect this and explicitly restore the parent window ourselves to avoid this situation. + if (cparent->WindowState() == Minimized) + cparent->SetWindowState(Normal); + [cparent->Window addChildWindow:Window ordered:NSWindowAbove]; UpdateStyle(); From 964121312c29c43ef743f7a2d0076ec268696838 Mon Sep 17 00:00:00 2001 From: Takoooooo Date: Sat, 14 Aug 2021 13:53:49 +0300 Subject: [PATCH 25/26] fix --- build/MicroCom.targets | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/MicroCom.targets b/build/MicroCom.targets index b48e377fd4..49d2cdce72 100644 --- a/build/MicroCom.targets +++ b/build/MicroCom.targets @@ -15,7 +15,8 @@ Inputs="@(AvnComIdl);$(MSBuildThisFileDirectory)../src/tools/MicroComGenerator/**/*.cs" Outputs="%(AvnComIdl.OutputFile)"> - + From 29f4806cfdeb1e59c36686b3f9d8264c009cfd19 Mon Sep 17 00:00:00 2001 From: Sergey Mikolaytis Date: Mon, 16 Aug 2021 09:01:07 +0300 Subject: [PATCH 26/26] [OSX] [Native] fix tab shortcuts in NativeMenu --- native/Avalonia.Native/src/OSX/KeyTransform.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/native/Avalonia.Native/src/OSX/KeyTransform.mm b/native/Avalonia.Native/src/OSX/KeyTransform.mm index 6b7d95b619..4817ad0ccf 100644 --- a/native/Avalonia.Native/src/OSX/KeyTransform.mm +++ b/native/Avalonia.Native/src/OSX/KeyTransform.mm @@ -222,6 +222,7 @@ std::map s_QwertyKeyMap = { 45, "n" }, { 46, "m" }, { 47, "." }, + { 48, "\t" }, { 49, " " }, { 50, "`" }, { 51, "" },