Browse Source

Merge branch 'master' into fixes/TextLineCaretNavigation

Benedikt Stebner 5 years ago
parent
commit
74a258a294

+ 11 - 1
Avalonia.sln

@@ -123,10 +123,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.NetCore", "s
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1-27F5-4255-9AFC-04ABFD11683A}"
 	ProjectSection(SolutionItems) = preProject
+		build\AndroidWorkarounds.props = build\AndroidWorkarounds.props
 		build\Base.props = build\Base.props
 		build\Binding.props = build\Binding.props
-		build\BuildTargets.targets = build\BuildTargets.targets
+		build\CoreLibraries.props = build\CoreLibraries.props
+		build\EmbedXaml.props = build\EmbedXaml.props
 		build\HarfBuzzSharp.props = build\HarfBuzzSharp.props
+		build\iOSWorkarounds.props = build\iOSWorkarounds.props
 		build\JetBrains.Annotations.props = build\JetBrains.Annotations.props
 		build\JetBrains.dotMemoryUnit.props = build\JetBrains.dotMemoryUnit.props
 		build\Magick.NET-Q16-AnyCPU.props = build\Magick.NET-Q16-AnyCPU.props
@@ -136,17 +139,24 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1
 		build\NetCore.props = build\NetCore.props
 		build\NetFX.props = build\NetFX.props
 		build\ReactiveUI.props = build\ReactiveUI.props
+		build\ReferenceCoreLibraries.props = build\ReferenceCoreLibraries.props
 		build\Rx.props = build\Rx.props
 		build\SampleApp.props = build\SampleApp.props
+		build\SharedVersion.props = build\SharedVersion.props
 		build\SharpDX.props = build\SharpDX.props
 		build\SkiaSharp.props = build\SkiaSharp.props
+		build\SourceLink.props = build\SourceLink.props
+		build\System.Drawing.Common.props = build\System.Drawing.Common.props
 		build\System.Memory.props = build\System.Memory.props
+		build\UnitTests.NetFX.props = build\UnitTests.NetFX.props
 		build\XUnit.props = build\XUnit.props
 	EndProjectSection
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Targets", "Targets", "{4D6FAF79-58B4-482F-9122-0668C346364C}"
 	ProjectSection(SolutionItems) = preProject
 		build\UnitTests.NetCore.targets = build\UnitTests.NetCore.targets
+		build\BuildTargets.targets = build\BuildTargets.targets
+		build\LegacyProject.targets = build\LegacyProject.targets
 	EndProjectSection
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Linux", "Linux", "{86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B}"

+ 30 - 1
samples/ControlCatalog/Pages/MenuPage.xaml

@@ -20,7 +20,9 @@
                         <Separator/>
                         <MenuItem Header="Menu with _Submenu">
                             <MenuItem Header="Submenu _1"/>
-                            <MenuItem Header="Submenu _2"/>
+                            <MenuItem Header="Submenu _2 with Submenu">
+                                <MenuItem Header="Submenu Level 2" />
+                            </MenuItem>
                         </MenuItem>
                         <MenuItem Header="Menu Item with _Icon" InputGesture="Ctrl+Shift+B">
                             <MenuItem.Icon>
@@ -52,6 +54,33 @@
                     </Menu.Styles>
                 </Menu>
             </StackPanel>
+        
+
+            <StackPanel>
+                <TextBlock Classes="h3" Margin="4 8">Mixed</TextBlock>
+                <Menu>
+                    <MenuItem Header="_File">
+                        <MenuItem Header="_New" CommandParameter="{Binding}" InputGesture="Ctrl+N"/>
+                        <Separator/>
+                        <MenuItem Header="_Open..." InputGesture="Ctrl+O"/>
+                        <Separator/>
+                        <MenuItem Header="Execu_te Script..." />
+                        <Separator/>
+                        <MenuItem Header="_Recent" Items="{Binding RecentItems}">
+                            <MenuItem.Styles>
+                                <Style Selector="MenuItem">
+                                    <Setter Property="Header" Value="{Binding Header}"/>
+                                </Style>
+                            </MenuItem.Styles>
+                        </MenuItem>
+                        <Separator/>
+                        <MenuItem Header="E_xit" InputGesture="Alt+F4"/>
+                    </MenuItem>
+                    <MenuItem Header="_Help">
+                        <MenuItem Header="_About"/>
+                    </MenuItem>
+                </Menu>
+            </StackPanel>
         </StackPanel>
     </StackPanel>
 </UserControl>

+ 20 - 16
samples/ControlCatalog/ViewModels/MenuPageViewModel.cs

@@ -17,6 +17,23 @@ namespace ControlCatalog.ViewModels
             SaveCommand = ReactiveCommand.Create(Save, Observable.Return(false));
             OpenRecentCommand = ReactiveCommand.Create<string>(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<MenuItemViewModel> MenuItems { get; set; }
+        public IReadOnlyList<MenuItemViewModel> RecentItems { get; set; }
         public ReactiveCommand<Unit, Unit> OpenCommand { get; }
         public ReactiveCommand<Unit, Unit> SaveCommand { get; }
         public ReactiveCommand<string, Unit> OpenRecentCommand { get; }

+ 2 - 4
src/Avalonia.Controls/Chrome/CaptionButtons.cs

@@ -38,12 +38,10 @@ namespace Avalonia.Controls.Chrome
         {
             if (_disposables != null)
             {
-                var layer = ChromeOverlayLayer.GetOverlayLayer(_hostWindow);
-
-                layer?.Children.Remove(this);
-
                 _disposables.Dispose();
                 _disposables = null;
+
+                _hostWindow = null;
             }
         }
 

+ 53 - 73
src/Avalonia.Controls/Chrome/TitleBar.cs

@@ -12,106 +12,86 @@ namespace Avalonia.Controls.Chrome
     public class TitleBar : TemplatedControl
     {
         private CompositeDisposable? _disposables;
-        private readonly Window? _hostWindow;
         private CaptionButtons? _captionButtons;
 
-        public TitleBar(Window hostWindow)
+        private void UpdateSize(Window window)
         {
-            _hostWindow = hostWindow;
-        }
-
-        public TitleBar()
-        {
-
-        }
-
-        public void Attach()
-        {
-            if (_disposables == null)
-            {
-                var layer = ChromeOverlayLayer.GetOverlayLayer(_hostWindow);
-
-                layer?.Children.Add(this);
-
-                if (_hostWindow != null)
-                {
-                    _disposables = new CompositeDisposable
-                    {
-                        _hostWindow.GetObservable(Window.WindowDecorationMarginProperty)
-                            .Subscribe(x => UpdateSize()),
-
-                        _hostWindow.GetObservable(Window.ExtendClientAreaTitleBarHeightHintProperty)
-                            .Subscribe(x => UpdateSize()),
-
-                        _hostWindow.GetObservable(Window.OffScreenMarginProperty)
-                            .Subscribe(x => UpdateSize()),
-
-                        _hostWindow.GetObservable(Window.WindowStateProperty)
-                            .Subscribe(x =>
-                            {
-                                PseudoClasses.Set(":minimized", x == WindowState.Minimized);
-                                PseudoClasses.Set(":normal", x == WindowState.Normal);
-                                PseudoClasses.Set(":maximized", x == WindowState.Maximized);
-                                PseudoClasses.Set(":fullscreen", x == WindowState.FullScreen);
-                            })
-                    };
-
-                    _captionButtons?.Attach(_hostWindow);
-                }
-
-                UpdateSize();
-            }
-        }
-
-        private void UpdateSize()
-        {
-            if (_hostWindow != null)
+            if (window != null)
             {
                 Margin = new Thickness(
-                    _hostWindow.OffScreenMargin.Left,
-                    _hostWindow.OffScreenMargin.Top,
-                    _hostWindow.OffScreenMargin.Right,
-                    _hostWindow.OffScreenMargin.Bottom);
+                    window.OffScreenMargin.Left,
+                    window.OffScreenMargin.Top,
+                    window.OffScreenMargin.Right,
+                    window.OffScreenMargin.Bottom);
 
-                if (_hostWindow.WindowState != WindowState.FullScreen)
+                if (window.WindowState != WindowState.FullScreen)
                 {
-                    Height = _hostWindow.WindowDecorationMargin.Top;
+                    Height = window.WindowDecorationMargin.Top;
 
                     if (_captionButtons != null)
                     {
                         _captionButtons.Height = Height;
                     }
                 }
+
+                IsVisible = window.PlatformImpl.NeedsManagedDecorations;
             }
         }
 
-        public void Detach()
+        protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
         {
-            if (_disposables != null)
-            {
-                var layer = ChromeOverlayLayer.GetOverlayLayer(_hostWindow);
-
-                layer?.Children.Remove(this);
+            base.OnApplyTemplate(e);
 
-                _disposables.Dispose();
-                _disposables = null;
+            _captionButtons?.Detach();
+            
+            _captionButtons = e.NameScope.Get<CaptionButtons>("PART_CaptionButtons");
 
-                _captionButtons?.Detach();
+            if (VisualRoot is Window window)
+            {
+                _captionButtons?.Attach(window);   
+                
+                UpdateSize(window);
             }
         }
 
-        protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
+        protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
         {
-            base.OnApplyTemplate(e);
-
-            _captionButtons = e.NameScope.Get<CaptionButtons>("PART_CaptionButtons");
+            base.OnAttachedToVisualTree(e);
 
-            if (_hostWindow != null)
+            if (VisualRoot is Window window)
             {
-                _captionButtons.Attach(_hostWindow);
+                _disposables = new CompositeDisposable
+                {
+                    window.GetObservable(Window.WindowDecorationMarginProperty)
+                        .Subscribe(x => UpdateSize(window)),
+                    window.GetObservable(Window.ExtendClientAreaTitleBarHeightHintProperty)
+                        .Subscribe(x => UpdateSize(window)),
+                    window.GetObservable(Window.OffScreenMarginProperty)
+                        .Subscribe(x => UpdateSize(window)),
+                    window.GetObservable(Window.ExtendClientAreaChromeHintsProperty)
+                        .Subscribe(x => UpdateSize(window)),
+                    window.GetObservable(Window.WindowStateProperty)
+                        .Subscribe(x =>
+                        {
+                            PseudoClasses.Set(":minimized", x == WindowState.Minimized);
+                            PseudoClasses.Set(":normal", x == WindowState.Normal);
+                            PseudoClasses.Set(":maximized", x == WindowState.Maximized);
+                            PseudoClasses.Set(":fullscreen", x == WindowState.FullScreen);
+                        }),
+                    window.GetObservable(Window.IsExtendedIntoWindowDecorationsProperty)
+                        .Subscribe(x => UpdateSize(window))
+                };
             }
+        }
+
+        protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
+        {
+            base.OnDetachedFromVisualTree(e);
 
-            UpdateSize();
+            _disposables?.Dispose();
+            
+            _captionButtons?.Detach();
+            _captionButtons = null;
         }
     }
 }

+ 18 - 33
src/Avalonia.Controls/DateTimePickers/TimePicker.cs

@@ -15,7 +15,7 @@ namespace Avalonia.Controls
         /// Defines the <see cref="MinuteIncrement"/> property
         /// </summary>
         public static readonly DirectProperty<TimePicker, int> MinuteIncrementProperty =
-            AvaloniaProperty.RegisterDirect<TimePicker, int>(nameof(MinuteIncrement), 
+            AvaloniaProperty.RegisterDirect<TimePicker, int>(nameof(MinuteIncrement),
                 x => x.MinuteIncrement, (x, v) => x.MinuteIncrement = v);
 
         /// <summary>
@@ -34,17 +34,17 @@ namespace Avalonia.Controls
         /// Defines the <see cref="ClockIdentifier"/> property
         /// </summary>
         public static readonly DirectProperty<TimePicker, string> ClockIdentifierProperty =
-           AvaloniaProperty.RegisterDirect<TimePicker, string>(nameof(ClockIdentifier), 
+           AvaloniaProperty.RegisterDirect<TimePicker, string>(nameof(ClockIdentifier),
                x => x.ClockIdentifier, (x, v) => x.ClockIdentifier = v);
 
         /// <summary>
         /// Defines the <see cref="SelectedTime"/> property
         /// </summary>
         public static readonly DirectProperty<TimePicker, TimeSpan?> SelectedTimeProperty =
-            AvaloniaProperty.RegisterDirect<TimePicker, TimeSpan?>(nameof(SelectedTime), 
+            AvaloniaProperty.RegisterDirect<TimePicker, TimeSpan?>(nameof(SelectedTime),
                 x => x.SelectedTime, (x, v) => x.SelectedTime = v);
 
-        //Template Items
+        // Template Items
         private TimePickerPresenter _presenter;
         private Button _flyoutButton;
         private Border _firstPickerHost;
@@ -52,7 +52,7 @@ namespace Avalonia.Controls
         private Border _thirdPickerHost;
         private TextBlock _hourText;
         private TextBlock _minuteText;
-        public TextBlock _periodText;
+        private TextBlock _periodText;
         private Rectangle _firstSplitter;
         private Rectangle _secondSplitter;
         private Grid _contentGrid;
@@ -145,7 +145,7 @@ namespace Avalonia.Controls
             if (_flyoutButton != null)
                 _flyoutButton.Click -= OnFlyoutButtonClicked;
 
-            if(_presenter != null)
+            if (_presenter != null)
             {
                 _presenter.Confirmed -= OnConfirmed;
                 _presenter.Dismissed -= OnDismissPicker;
@@ -170,7 +170,6 @@ namespace Avalonia.Controls
             _popup = e.NameScope.Find<Popup>("Popup");
             _presenter = e.NameScope.Find<TimePickerPresenter>("PickerPresenter");
 
-
             if (_flyoutButton != null)
                 _flyoutButton.Click += OnFlyoutButtonClicked;
 
@@ -185,7 +184,6 @@ namespace Avalonia.Controls
                 _presenter[!TimePickerPresenter.MinuteIncrementProperty] = this[!MinuteIncrementProperty];
                 _presenter[!TimePickerPresenter.ClockIdentifierProperty] = this[!ClockIdentifierProperty];
             }
-
         }
 
         private void SetGrid()
@@ -195,30 +193,19 @@ namespace Avalonia.Controls
 
             bool use24HourClock = ClockIdentifier == "24HourClock";
 
-            if (!use24HourClock)
-            {
-                _contentGrid.ColumnDefinitions = new ColumnDefinitions("*,Auto,*,Auto,*");
-                _thirdPickerHost.IsVisible = true;
-                _secondSplitter.IsVisible = true;
+            var columnsD = use24HourClock ? "*, Auto, *" : "*, Auto, *, Auto, *";
+            _contentGrid.ColumnDefinitions = new ColumnDefinitions(columnsD);
 
-                Grid.SetColumn(_firstPickerHost, 0);
-                Grid.SetColumn(_secondPickerHost, 2);
-                Grid.SetColumn(_thirdPickerHost, 4);
+            _thirdPickerHost.IsVisible = !use24HourClock;
+            _secondSplitter.IsVisible = !use24HourClock;
 
-                Grid.SetColumn(_firstSplitter, 1);
-                Grid.SetColumn(_secondSplitter, 3);
-            }
-            else
-            {
-                _contentGrid.ColumnDefinitions = new ColumnDefinitions("*,Auto,*");
-                _thirdPickerHost.IsVisible = false;
-                _secondSplitter.IsVisible = false;
+            Grid.SetColumn(_firstPickerHost, 0);
+            Grid.SetColumn(_secondPickerHost, 2);
 
-                Grid.SetColumn(_firstPickerHost, 0);
-                Grid.SetColumn(_secondPickerHost, 2);
+            Grid.SetColumn(_thirdPickerHost, use24HourClock ? 0 : 4);
 
-                Grid.SetColumn(_firstSplitter, 1);
-            }
+            Grid.SetColumn(_firstSplitter, 1);
+            Grid.SetColumn(_secondSplitter, use24HourClock ? 0 : 3);
         }
 
         private void SetSelectedTimeText()
@@ -237,14 +224,13 @@ namespace Avalonia.Controls
                     hr = hr > 12 ? hr - 12 : hr == 0 ? 12 : hr;
                     newTime = new TimeSpan(hr, newTime.Minutes, 0);
                 }
-                _hourText.Text = newTime.ToString("%h");
 
+                _hourText.Text = newTime.ToString("%h");
                 _minuteText.Text = newTime.ToString("mm");
                 PseudoClasses.Set(":hasnotime", false);
 
                 _periodText.Text = time.Value.Hours >= 12 ? CultureInfo.CurrentCulture.DateTimeFormat.PMDesignator :
                     CultureInfo.CurrentCulture.DateTimeFormat.AMDesignator;
-
             }
             else
             {
@@ -262,7 +248,7 @@ namespace Avalonia.Controls
             SelectedTimeChanged?.Invoke(this, new TimePickerSelectedValueChangedEventArgs(oldTime, newTime));
         }
 
-        private void OnFlyoutButtonClicked(object sender, Avalonia.Interactivity.RoutedEventArgs e)
+        private void OnFlyoutButtonClicked(object sender, Interactivity.RoutedEventArgs e)
         {
             _presenter.Time = SelectedTime ?? DateTime.Now.TimeOfDay;
 
@@ -270,7 +256,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);
@@ -287,6 +273,5 @@ namespace Avalonia.Controls
             _popup.Close();
             SelectedTime = _presenter.Time;
         }
-
     }
 }

+ 18 - 20
src/Avalonia.Controls/DateTimePickers/TimePickerPresenter.cs

@@ -39,7 +39,7 @@ namespace Avalonia.Controls
             KeyboardNavigation.SetTabNavigation(this, KeyboardNavigationMode.Cycle);
         }
 
-        //TemplateItems
+        // TemplateItems
         private Grid _pickerContainer;
         private Button _acceptButton;
         private Button _dismissButton;
@@ -55,8 +55,8 @@ namespace Avalonia.Controls
         private Button _minuteDownButton;
         private Button _periodDownButton;
 
-        //Backing Fields
-        private TimeSpan _Time;
+        // Backing Fields
+        private TimeSpan _time;
         private int _minuteIncrement = 1;
         private string _clockIdentifier = "12HourClock";
 
@@ -83,7 +83,7 @@ namespace Avalonia.Controls
             get => _clockIdentifier;
             set
             {
-                if (string.IsNullOrEmpty(value) || value == "" || !(value == "12HourClock" || value == "24HourClock"))
+                if (string.IsNullOrEmpty(value) || !(value == "12HourClock" || value == "24HourClock"))
                     throw new ArgumentException("Invalid ClockIdentifier");
                 SetAndRaise(ClockIdentifierProperty, ref _clockIdentifier, value);
                 InitPicker();
@@ -95,10 +95,10 @@ namespace Avalonia.Controls
         /// </summary>
         public TimeSpan Time
         {
-            get => _Time;
+            get => _time;
             set
             {
-                SetAndRaise(TimeProperty, ref _Time, value);
+                SetAndRaise(TimeProperty, ref _time, value);
                 InitPicker();
             }
         }
@@ -213,26 +213,24 @@ namespace Avalonia.Controls
 
         private void SetGrid()
         {
-            if (ClockIdentifier == "12HourClock")
-            {
-                _pickerContainer.ColumnDefinitions = new ColumnDefinitions("*,Auto,*,Auto,*");
-                _spacer2.IsVisible = true;
-                _periodHost.IsVisible = true;
-            }
-            else
-            {
-                _pickerContainer.ColumnDefinitions = new ColumnDefinitions("*,Auto,*");
-                _spacer2.IsVisible = false;
-                _periodHost.IsVisible = false;
-            }
+            bool use24HourClock = ClockIdentifier == "24HourClock";
+
+            var columnsD = use24HourClock ? "*, Auto, *" : "*, Auto, *, Auto, *";
+            _pickerContainer.ColumnDefinitions = new ColumnDefinitions(columnsD);
+
+            _spacer2.IsVisible = !use24HourClock;
+            _periodHost.IsVisible = !use24HourClock;
+
+            Grid.SetColumn(_spacer2, use24HourClock ? 0 : 3);
+            Grid.SetColumn(_periodHost, use24HourClock ? 0 : 4);
         }
 
-        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)
         {
             OnConfirmed();
         }

+ 6 - 1
src/Avalonia.Controls/Primitives/ChromeOverlayLayer.cs

@@ -8,7 +8,7 @@ namespace Avalonia.Controls.Primitives
 {
     public class ChromeOverlayLayer : Panel, ICustomSimpleHitTest
     {
-        public static ChromeOverlayLayer? GetOverlayLayer(IVisual visual)
+        public static Panel? GetOverlayLayer(IVisual visual)
         {
             foreach (var v in visual.GetVisualAncestors())
                 if (v is VisualLayerManager vlm)
@@ -24,6 +24,11 @@ namespace Avalonia.Controls.Primitives
             return null;
         }
 
+        public void Add(Control c)
+        {
+            base.Children.Add(c);
+        }
+
         public bool HitTest(Point point) => Children.HitTestCustom(point);
     }
 }

+ 21 - 8
src/Avalonia.Controls/Primitives/VisualLayerManager.cs

@@ -1,5 +1,6 @@
 using System.Collections.Generic;
 using Avalonia.LogicalTree;
+using Avalonia.Metadata;
 
 namespace Avalonia.Controls.Primitives
 {
@@ -11,10 +12,12 @@ namespace Avalonia.Controls.Primitives
 
         private ILogicalRoot _logicalRoot;
         private readonly List<Control> _layers = new List<Control>();
-        
+
+        public static readonly StyledProperty<ChromeOverlayLayer> ChromeOverlayLayerProperty =
+            AvaloniaProperty.Register<VisualLayerManager, ChromeOverlayLayer>(nameof(ChromeOverlayLayer));
 
         public bool IsPopup { get; set; }
-        
+
         public AdornerLayer AdornerLayer
         {
             get
@@ -30,10 +33,19 @@ namespace Avalonia.Controls.Primitives
         {
             get
             {
-                var rv = FindLayer<ChromeOverlayLayer>();
-                if (rv == null)
-                    AddLayer(rv = new ChromeOverlayLayer(), ChromeZIndex);
-                return rv;
+                var current = GetValue(ChromeOverlayLayerProperty);
+
+                if (current is null)
+                {
+                    var chromeOverlayLayer = new ChromeOverlayLayer();
+                    AddLayer(chromeOverlayLayer, ChromeZIndex);
+
+                    SetValue(ChromeOverlayLayerProperty, chromeOverlayLayer);
+
+                    current = chromeOverlayLayer;
+                }
+
+                return current;
             }
         }
 
@@ -44,7 +56,7 @@ namespace Avalonia.Controls.Primitives
                 if (IsPopup)
                     return null;
                 var rv = FindLayer<OverlayLayer>();
-                if(rv == null)
+                if (rv == null)
                     AddLayer(rv = new OverlayLayer(), OverlayZIndex);
                 return rv;
             }
@@ -65,7 +77,8 @@ namespace Avalonia.Controls.Primitives
             layer.ZIndex = zindex;
             VisualChildren.Add(layer);
             if (((ILogical)this).IsAttachedToLogicalTree)
-                ((ILogical)layer).NotifyAttachedToLogicalTree(new LogicalTreeAttachmentEventArgs(_logicalRoot, layer, this));
+                ((ILogical)layer).NotifyAttachedToLogicalTree(
+                    new LogicalTreeAttachmentEventArgs(_logicalRoot, layer, this));
             InvalidateArrange();
         }
 

+ 2 - 16
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;
@@ -70,8 +71,7 @@ namespace Avalonia.Controls
     /// </summary>
     public class Window : WindowBase, IStyleable, IFocusScope, ILayoutRoot
     {
-        private readonly List<(Window child, bool isDialog)> _children = new List<(Window, bool)>();        
-        private TitleBar _managedTitleBar;
+        private readonly List<(Window child, bool isDialog)> _children = new List<(Window, bool)>();
         private bool _isExtendedIntoWindowDecorations;
         private Thickness _windowDecorationMargin;
         private Thickness _offScreenMargin;
@@ -552,20 +552,6 @@ namespace Avalonia.Controls
             IsExtendedIntoWindowDecorations = isExtended;
             WindowDecorationMargin = PlatformImpl.ExtendedMargins;
             OffScreenMargin = PlatformImpl.OffScreenMargin;
-
-            if (PlatformImpl.NeedsManagedDecorations)
-            {
-                if (_managedTitleBar == null)
-                {
-                    _managedTitleBar = new TitleBar(this);
-                    _managedTitleBar.Attach();
-                }                
-            }
-            else
-            {
-                _managedTitleBar?.Detach();
-                _managedTitleBar = null;
-            }
         }
 
         /// <summary>

+ 5 - 0
src/Avalonia.Native/OsxUnicodeKeys.cs

@@ -140,6 +140,11 @@ namespace Avalonia.Native.Interop
             }
             else
             {
+                if (key >= Key.D0 && key <= Key.D9)
+                {
+                    return key.ToString().Replace("D", "");
+                }
+                
                 return key.ToString().ToLower();
             }
         }

+ 18 - 16
src/Avalonia.Themes.Default/Window.xaml

@@ -1,23 +1,25 @@
 <Style xmlns="https://github.com/avaloniaui" Selector="Window">
-  <Setter Property="Background" Value="{DynamicResource ThemeBackgroundBrush}"/>
-  <Setter Property="Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
-  <Setter Property="FontSize" Value="{DynamicResource FontSizeNormal}"/>
+  <Setter Property="Background" Value="{DynamicResource SystemControlBackgroundAltHighBrush}"/>  
+  <Setter Property="TransparencyBackgroundFallback" Value="{DynamicResource SystemControlBackgroundAltHighBrush}" />
+  <Setter Property="Foreground" Value="{DynamicResource SystemControlForegroundBaseHighBrush}"/>
+  <Setter Property="FontSize" Value="{DynamicResource ContentControlFontSize}"/>  
+  <Setter Property="FontFamily" Value="{DynamicResource ContentControlThemeFontFamily}" />
   <Setter Property="Template">
     <ControlTemplate>
       <Panel>
-        <Panel IsHitTestVisible="False" Margin="{TemplateBinding OffScreenMargin}">
-          <Border Name="PART_TransparencyFallback" IsHitTestVisible="False" />
-        </Panel>
-        <Border Background="{TemplateBinding Background}">
-          <VisualLayerManager>
-            <ContentPresenter Name="PART_ContentPresenter"
-                              ContentTemplate="{TemplateBinding ContentTemplate}"
-                              Content="{TemplateBinding Content}"
-                              Margin="{TemplateBinding Padding}"
-                              HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
-                              VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
-          </VisualLayerManager>
-        </Border>
+        <Border Name="PART_TransparencyFallback" IsHitTestVisible="False" />
+        <Border Background="{TemplateBinding Background}" IsHitTestVisible="False" />
+        <VisualLayerManager>
+          <VisualLayerManager.ChromeOverlayLayer>
+            <TitleBar />
+          </VisualLayerManager.ChromeOverlayLayer>
+          <ContentPresenter Name="PART_ContentPresenter"
+                            ContentTemplate="{TemplateBinding ContentTemplate}"
+                            Content="{TemplateBinding Content}"
+                            Margin="{TemplateBinding Padding}"
+                            HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
+                            VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
+        </VisualLayerManager>
       </Panel>
     </ControlTemplate>
   </Setter>

+ 4 - 2
src/Avalonia.Themes.Fluent/Menu.xaml

@@ -11,10 +11,12 @@
   </Design.PreviewWith>
 
   <Style.Resources>
-    <x:Double x:Key="MenuHeight">32</x:Double>
+    <x:Double x:Key="MenuBarHeight">32</x:Double>
+    <Thickness x:Key="MenuBarItemPadding">12,0,12,0</Thickness>
   </Style.Resources>
+
   <Setter Property="Background" Value="Transparent" />
-  <Setter Property="Height" Value="{StaticResource MenuHeight}" />
+  <Setter Property="Height" Value="{StaticResource MenuBarHeight}" />
   <Setter Property="Template">
     <ControlTemplate>
       <Border Background="{TemplateBinding Background}"

+ 97 - 87
src/Avalonia.Themes.Fluent/MenuItem.xaml

@@ -25,11 +25,12 @@
         </MenuItem>
         <MenuItem Header="Edit">
           <MenuItem Header="Go To">
-            <MenuItem Header="Go To Line"/>
+            <MenuItem Header="Go To Line" />
           </MenuItem>
         </MenuItem>
         <MenuItem Header="View">
-          <MenuItem Header="Designer" InputGesture="Shift+F7" />
+          <MenuItem Header="Designer"
+                    InputGesture="Shift+F7" />
         </MenuItem>
         <MenuItem Header="Project">
           <MenuItem Header="Add class" />
@@ -40,9 +41,10 @@
 
   <Styles.Resources>
     <conv:PlatformKeyGestureConverter x:Key="KeyGestureConverter" />
+    <x:Double x:Key="MenuFlyoutSubItemPopupHorizontalOffset">-4</x:Double>
     <Thickness x:Key="MenuFlyoutScrollerMargin">0,4,0,4</Thickness>
     <Thickness x:Key="MenuIconPresenterMargin">0,0,12,0</Thickness>
-    <Thickness x:Key="MenuInputGestureTextMargin">24,0,0,0</Thickness>    
+    <Thickness x:Key="MenuInputGestureTextMargin">24,0,0,0</Thickness>
     <StreamGeometry x:Key="MenuItemChevronPathData">M 1,0 10,10 l -9,10 -1,-1 L 8,10 -0,1 Z</StreamGeometry>
   </Styles.Resources>
 
@@ -54,83 +56,84 @@
     <Setter Property="FontSize" Value="{DynamicResource ControlContentThemeFontSize}" />
     <Setter Property="Template">
       <ControlTemplate>
-        <Border Name="PART_LayoutRoot"
-                Padding="{TemplateBinding Padding}"
-                Background="{TemplateBinding Background}"
-                BorderBrush="{TemplateBinding BorderBrush}"
-                BorderThickness="{TemplateBinding BorderThickness}">
-          <Grid>
-            <Grid.ColumnDefinitions>
-              <ColumnDefinition Width="Auto"
-                                SharedSizeGroup="MenuItemIcon"  />
-              <ColumnDefinition Width="*" />
-              <ColumnDefinition Width="Auto"
-                                SharedSizeGroup="MenuItemIGT" />
-              <ColumnDefinition Width="Auto"
-                                SharedSizeGroup="MenuItemChevron" />
-            </Grid.ColumnDefinitions>
-            <ContentPresenter Name="PART_IconPresenter"
-                              Content="{TemplateBinding Icon}"
-                              Width="16"
-                              Height="16"
-                              Margin="{DynamicResource MenuIconPresenterMargin}"
-                              HorizontalAlignment="Center"
-                              VerticalAlignment="Center"/>
+        <Panel>
+          <Border Name="PART_LayoutRoot"
+                  Padding="{TemplateBinding Padding}"
+                  Background="{TemplateBinding Background}"
+                  BorderBrush="{TemplateBinding BorderBrush}"
+                  BorderThickness="{TemplateBinding BorderThickness}">
+            <Grid>
+              <Grid.ColumnDefinitions>
+                <ColumnDefinition Width="Auto"
+                                  SharedSizeGroup="MenuItemIcon" />
+                <ColumnDefinition Width="*" />
+                <ColumnDefinition Width="Auto"
+                                  SharedSizeGroup="MenuItemIGT" />
+                <ColumnDefinition Width="Auto"
+                                  SharedSizeGroup="MenuItemChevron" />
+              </Grid.ColumnDefinitions>
+              <ContentPresenter Name="PART_IconPresenter"
+                                Content="{TemplateBinding Icon}"
+                                Width="16"
+                                Height="16"
+                                Margin="{DynamicResource MenuIconPresenterMargin}"
+                                HorizontalAlignment="Center"
+                                VerticalAlignment="Center" />
 
-            <ContentPresenter Name="PART_HeaderPresenter"
-                              Content="{TemplateBinding Header}"
-                              VerticalAlignment="Center"
-                              HorizontalAlignment="Stretch"
-                              TextBlock.Foreground="{TemplateBinding Foreground}"
-                              Grid.Column="1">
-              <ContentPresenter.DataTemplates>
-                <DataTemplate DataType="sys:String">
-                  <AccessText Text="{Binding}" />
-                </DataTemplate>
-              </ContentPresenter.DataTemplates>
-            </ContentPresenter>
-            <TextBlock x:Name="PART_InputGestureText"
-                       Grid.Column="2"
-                       Classes="CaptionTextBlockStyle"
-                       Margin="{DynamicResource MenuInputGestureTextMargin}"
-                       Text="{TemplateBinding InputGesture,
-                                              Converter={StaticResource KeyGestureConverter}}"
-                       HorizontalAlignment="Right"
-                       VerticalAlignment="Center" />
-            <Path Name="PART_ChevronPath"
-                  Stretch="Uniform"
-                  Width="8"
-                  Height="16"
-                  Data="{StaticResource MenuItemChevronPathData}"
-                  Margin="{DynamicResource MenuFlyoutItemChevronMargin}"
-                  VerticalAlignment="Center"
-                  Grid.Column="3" />
-            <Popup Name="PART_Popup"
-                   WindowManagerAddShadowHint="True"
-                   PlacementMode="Right"
-                   StaysOpen="True"
-                   IsOpen="{TemplateBinding IsSubMenuOpen,
-                                            Mode=TwoWay}">
-              <Border Background="{DynamicResource MenuFlyoutPresenterBackground}"
-                      BorderBrush="{DynamicResource MenuFlyoutPresenterBorderBrush}"
-                      BorderThickness="{DynamicResource MenuFlyoutPresenterBorderThemeThickness}"
-                      Padding="{DynamicResource MenuFlyoutPresenterThemePadding}"
-                      MaxWidth="{DynamicResource FlyoutThemeMaxWidth}"
-                      MinHeight="{DynamicResource MenuFlyoutThemeMinHeight}"
-                      HorizontalAlignment="Stretch"
-                      CornerRadius="{DynamicResource OverlayCornerRadius}">
-                <ScrollViewer>
-                  <ItemsPresenter Name="PART_ItemsPresenter"
-                                  Items="{TemplateBinding Items}"
-                                  ItemsPanel="{TemplateBinding ItemsPanel}"
-                                  ItemTemplate="{TemplateBinding ItemTemplate}"
-                                  Margin="{DynamicResource MenuFlyoutScrollerMargin}"
-                                  Grid.IsSharedSizeScope="True" />
-                </ScrollViewer>
-              </Border>
-            </Popup>
-          </Grid>
-        </Border>
+              <ContentPresenter Name="PART_HeaderPresenter"
+                                Content="{TemplateBinding Header}"
+                                VerticalAlignment="Center"
+                                HorizontalAlignment="Stretch"
+                                TextBlock.Foreground="{TemplateBinding Foreground}"
+                                Grid.Column="1">
+                <ContentPresenter.DataTemplates>
+                  <DataTemplate DataType="sys:String">
+                    <AccessText Text="{Binding}" />
+                  </DataTemplate>
+                </ContentPresenter.DataTemplates>
+              </ContentPresenter>
+              <TextBlock x:Name="PART_InputGestureText"
+                         Grid.Column="2"
+                         Classes="CaptionTextBlockStyle"
+                         Margin="{DynamicResource MenuInputGestureTextMargin}"
+                         Text="{TemplateBinding InputGesture, Converter={StaticResource KeyGestureConverter}}"
+                         HorizontalAlignment="Right"
+                         VerticalAlignment="Center" />
+              <Path Name="PART_ChevronPath"
+                    Stretch="Uniform"
+                    Width="8"
+                    Height="16"
+                    Data="{StaticResource MenuItemChevronPathData}"
+                    Margin="{DynamicResource MenuFlyoutItemChevronMargin}"
+                    VerticalAlignment="Center"
+                    Grid.Column="3" />
+            </Grid>
+          </Border>
+          <Popup Name="PART_Popup"
+                 WindowManagerAddShadowHint="True"
+                 PlacementMode="Right"
+                 HorizontalOffset="{StaticResource MenuFlyoutSubItemPopupHorizontalOffset}"
+                 StaysOpen="True"
+                 IsOpen="{TemplateBinding IsSubMenuOpen, Mode=TwoWay}">
+            <Border Background="{DynamicResource MenuFlyoutPresenterBackground}"
+                    BorderBrush="{DynamicResource MenuFlyoutPresenterBorderBrush}"
+                    BorderThickness="{DynamicResource MenuFlyoutPresenterBorderThemeThickness}"
+                    Padding="{DynamicResource MenuFlyoutPresenterThemePadding}"
+                    MaxWidth="{DynamicResource FlyoutThemeMaxWidth}"
+                    MinHeight="{DynamicResource MenuFlyoutThemeMinHeight}"
+                    HorizontalAlignment="Stretch"
+                    CornerRadius="{DynamicResource OverlayCornerRadius}">
+              <ScrollViewer>
+                <ItemsPresenter Name="PART_ItemsPresenter"
+                                Items="{TemplateBinding Items}"
+                                ItemsPanel="{TemplateBinding ItemsPanel}"
+                                ItemTemplate="{TemplateBinding ItemTemplate}"
+                                Margin="{DynamicResource MenuFlyoutScrollerMargin}"
+                                Grid.IsSharedSizeScope="True" />
+              </ScrollViewer>
+            </Border>
+          </Popup>
+        </Panel>
       </ControlTemplate>
     </Setter>
   </Style>
@@ -145,6 +148,8 @@
           <Panel>
             <ContentPresenter Name="PART_HeaderPresenter"
                               Content="{TemplateBinding Header}"
+                              VerticalAlignment="Center"
+                              HorizontalAlignment="Stretch"
                               Margin="{TemplateBinding Padding}">
               <ContentPresenter.DataTemplates>
                 <DataTemplate DataType="sys:String">
@@ -155,8 +160,7 @@
             <Popup Name="PART_Popup"
                    WindowManagerAddShadowHint="False"
                    MinWidth="{Binding Bounds.Width, RelativeSource={RelativeSource TemplatedParent}}"
-                   IsOpen="{TemplateBinding IsSubMenuOpen,
-                                            Mode=TwoWay}"
+                   IsOpen="{TemplateBinding IsSubMenuOpen, Mode=TwoWay}"
                    StaysOpen="True">
               <Border Background="{DynamicResource MenuFlyoutPresenterBackground}"
                       BorderBrush="{DynamicResource MenuFlyoutPresenterBorderBrush}"
@@ -183,10 +187,15 @@
   </Style>
 
   <Style Selector="MenuItem">
-    <!-- Narrow padding should be used for mouse input, when non-narrow one should be used for touch input in future. -->
-    <Setter Property="Padding" Value="{DynamicResource MenuFlyoutItemThemePaddingNarrow}" />
+    <!--  Narrow padding should be used for mouse input, when non-narrow one should be used for touch input in future.  -->
+    <Setter Property="Padding" Value="{StaticResource MenuFlyoutItemThemePaddingNarrow}" />
   </Style>
-  
+
+  <Style Selector="Menu > MenuItem">
+    <!--  Custom padding for Menu > MenuItem  -->
+    <Setter Property="Padding" Value="{StaticResource MenuBarItemPadding}" />
+  </Style>
+
   <Style Selector="MenuItem /template/ ContentPresenter#PART_IconPresenter">
     <Setter Property="IsVisible" Value="False" />
   </Style>
@@ -212,14 +221,15 @@
     <Setter Property="Fill" Value="{DynamicResource MenuFlyoutSubItemChevronPointerOver}" />
   </Style>
 
-  <Style Selector="MenuItem:pressed /template/ Border#PART_LayoutRoot">
+  <!--  Listen for PART_LayoutRoot:pointerover, so it will not be triggered when subitem is pressed  -->
+  <Style Selector="MenuItem:pressed /template/ Border#PART_LayoutRoot:pointerover">
     <Setter Property="Background" Value="{DynamicResource MenuFlyoutItemBackgroundPressed}" />
     <Setter Property="BorderBrush" Value="{DynamicResource MenuFlyoutItemBorderBrushPressed}" />
   </Style>
-  <Style Selector="MenuItem:pressed /template/ TextBlock#PART_InputGestureText">
+  <Style Selector="MenuItem:pressed /template/ Border#PART_LayoutRoot:pointerover TextBlock#PART_InputGestureText">
     <Setter Property="Foreground" Value="{DynamicResource MenuFlyoutItemKeyboardAcceleratorTextForegroundPressed}" />
   </Style>
-  <Style Selector="MenuItem:pressed /template/ Path#PART_ChevronPath">
+  <Style Selector="MenuItem:pressed /template/ Border#PART_LayoutRoot:pointerover Path#PART_ChevronPath">
     <Setter Property="Fill" Value="{DynamicResource MenuFlyoutSubItemChevronPressed}" />
   </Style>
 

+ 1 - 1
src/Avalonia.Themes.Fluent/NumericUpDown.xaml

@@ -43,7 +43,7 @@
           <TextBox Name="PART_TextBox"
                    Background="Transparent"
                    BorderBrush="Transparent"
-                   Margin="-2"
+                   Margin="-1"
                    Padding="{TemplateBinding Padding}"
                    Watermark="{TemplateBinding Watermark}"
                    DataValidationErrors.Errors="{TemplateBinding (DataValidationErrors.Errors)}"

+ 12 - 10
src/Avalonia.Themes.Fluent/Window.xaml

@@ -8,16 +8,18 @@
     <ControlTemplate>
       <Panel>
         <Border Name="PART_TransparencyFallback" IsHitTestVisible="False" />
-        <Border Background="{TemplateBinding Background}">
-          <VisualLayerManager>
-            <ContentPresenter Name="PART_ContentPresenter"
-                              ContentTemplate="{TemplateBinding ContentTemplate}"
-                              Content="{TemplateBinding Content}"
-                              Margin="{TemplateBinding Padding}"
-                              HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
-                              VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
-          </VisualLayerManager>
-        </Border>
+        <Border Background="{TemplateBinding Background}" IsHitTestVisible="False" />
+        <VisualLayerManager>
+          <VisualLayerManager.ChromeOverlayLayer>
+            <TitleBar />
+          </VisualLayerManager.ChromeOverlayLayer>
+          <ContentPresenter Name="PART_ContentPresenter"
+                            ContentTemplate="{TemplateBinding ContentTemplate}"
+                            Content="{TemplateBinding Content}"
+                            Margin="{TemplateBinding Padding}"
+                            HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
+                            VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
+        </VisualLayerManager>
       </Panel>
     </ControlTemplate>
   </Setter>