瀏覽代碼

Merge branch 'master' into refactor/remove_duplicate_math_utils

Dariusz Komosiński 5 年之前
父節點
當前提交
f5cb9f3290
共有 30 個文件被更改,包括 2004 次插入342 次删除
  1. 19 14
      readme.md
  2. 1 1
      samples/ControlCatalog/Pages/ToolTipPage.xaml
  3. 153 14
      src/Avalonia.Controls/ContextMenu.cs
  4. 5 0
      src/Avalonia.Controls/MenuItem.cs
  5. 53 2
      src/Avalonia.Controls/Primitives/IPopupHost.cs
  6. 6 6
      src/Avalonia.Controls/Primitives/OverlayPopupHost.cs
  7. 98 19
      src/Avalonia.Controls/Primitives/Popup.cs
  8. 287 137
      src/Avalonia.Controls/Primitives/PopupPositioning/IPopupPositioner.cs
  9. 86 31
      src/Avalonia.Controls/Primitives/PopupPositioning/ManagedPopupPositioner.cs
  10. 2 4
      src/Avalonia.Controls/Primitives/PopupPositioning/ManagedPopupPositionerPopupImplHelper.cs
  11. 5 3
      src/Avalonia.Controls/Primitives/PopupRoot.cs
  12. 1 1
      src/Avalonia.Controls/Primitives/Track.cs
  13. 1 1
      src/Avalonia.Controls/Slider.cs
  14. 105 0
      src/Avalonia.Controls/ToggleSwitch.cs
  15. 1 2
      src/Avalonia.Native/OsxManagedPopupPositionerPopupImplHelper.cs
  16. 1 0
      src/Avalonia.Themes.Default/DefaultTheme.xaml
  17. 294 0
      src/Avalonia.Themes.Default/ToggleSwitch.xaml
  18. 3 0
      src/Avalonia.Themes.Fluent/Accents/BaseDark.xaml
  19. 3 0
      src/Avalonia.Themes.Fluent/Accents/BaseLight.xaml
  20. 151 6
      src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesDark.xaml
  21. 150 6
      src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesLight.xaml
  22. 6 0
      src/Avalonia.Themes.Fluent/Common.xaml
  23. 54 15
      src/Avalonia.Themes.Fluent/ContextMenu.xaml
  24. 1 0
      src/Avalonia.Themes.Fluent/FluentTheme.xaml
  25. 23 5
      src/Avalonia.Themes.Fluent/Menu.xaml
  26. 178 66
      src/Avalonia.Themes.Fluent/MenuItem.xaml
  27. 5 7
      src/Avalonia.Themes.Fluent/Separator.xaml
  28. 294 0
      src/Avalonia.Themes.Fluent/ToggleSwitch.xaml
  29. 17 1
      src/Avalonia.X11/XI2Manager.cs
  30. 1 1
      src/Windows/Avalonia.Win32/WindowImpl.cs

+ 19 - 14
readme.md

@@ -1,24 +1,20 @@
-<img src='https://avatars2.githubusercontent.com/u/14075148?s=200&v=4' width='100' />
+[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/AvaloniaUI/Avalonia?utm_campaign=pr-badge&utm_content=badge&utm_medium=badge&utm_source=badge) [![Build Status](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_apis/build/status/AvaloniaUI.Avalonia)](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_build/latest?definitionId=4) [![Backers on Open Collective](https://opencollective.com/Avalonia/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/Avalonia/sponsors/badge.svg)](#sponsors) ![License](https://img.shields.io/github/license/avaloniaui/avalonia.svg)
+<br />
+[![NuGet](https://img.shields.io/nuget/v/Avalonia.svg)](https://www.nuget.org/packages/Avalonia) [![downloads](https://img.shields.io/nuget/dt/avalonia)](https://www.nuget.org/packages/Avalonia) [![MyGet](https://img.shields.io/myget/avalonia-ci/vpre/Avalonia.svg?label=myget)](https://www.myget.org/gallery/avalonia-ci) ![Size](https://img.shields.io/github/repo-size/avaloniaui/avalonia.svg) 
 
 
-# Avalonia
+<img src="https://user-images.githubusercontent.com/6759207/84750966-ac74ad80-afc4-11ea-97a4-067d99c15a7d.png" width="500"/>
 
 
-| Gitter Chat | Build Status (Win, Linux, OSX) | Open Collective | NuGet | MyGet |
-|---|---|---|---|---|
-|  [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/AvaloniaUI/Avalonia?utm_campaign=pr-badge&utm_content=badge&utm_medium=badge&utm_source=badge) | [![Build Status](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_apis/build/status/AvaloniaUI.Avalonia)](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_build/latest?definitionId=4) | [![Backers on Open Collective](https://opencollective.com/Avalonia/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/Avalonia/sponsors/badge.svg)](#sponsors) | [![NuGet](https://img.shields.io/nuget/v/Avalonia.svg)](https://www.nuget.org/packages/Avalonia) | [![MyGet](https://img.shields.io/myget/avalonia-ci/vpre/Avalonia.svg?label=myget)](https://www.myget.org/gallery/avalonia-ci) |
+## 📖 About AvaloniaUI 
 
 
-## About
+Avalonia is a cross-platform XAML-based UI framework providing a flexible styling system and supporting a wide range of Operating Systems such as Windows via .NET Framework and .NET Core, Linux via Xorg, macOS. Avalonia is ready for **General-Purpose Desktop App Development**. However, there may be some bugs and breaking changes as we continue along into this project's development. 
 
 
-**Avalonia** is a cross-platform XAML-based UI framework providing a flexible styling system and supporting a wide range of Operating Systems such as Windows (.NET Framework, .NET Core), Linux (via Xorg), macOS.
+<img src="https://user-images.githubusercontent.com/6759207/84751662-7c79da00-afc5-11ea-8780-dda28db70b76.png" width="700" />
 
 
-**Avalonia** is ready for **General-Purpose Desktop App Development**. However, there may be some bugs and breaking changes as we continue along into this project's development.
+> **Note:** The UI theme you see in the picture above is still work-in-progress and will be available in the upcoming Avalonia 0.10.0 release. However, you can connect to our nightly build feed and install latest pre-release versions of Avalonia NuGet packages, if you are willing to help out with the development and testing. See [Using nightly build feed](https://github.com/AvaloniaUI/Avalonia/wiki/Using-nightly-build-feed) for more info.
 
 
-To see the status of some of our features, please see our [Roadmap here](https://github.com/AvaloniaUI/Avalonia/issues/2239).
+To see the status of some of our features, please see our [Roadmap](https://github.com/AvaloniaUI/Avalonia/issues/2239). You can also see what [breaking changes](https://github.com/AvaloniaUI/Avalonia/issues/3538) we have planned and what our [past breaking changes](https://github.com/AvaloniaUI/Avalonia/wiki/Breaking-Changes) have been. [Awesome Avalonia](https://github.com/AvaloniaCommunity/awesome-avalonia) is community-curated list of awesome Avalonia UI tools, libraries, projects and resources. Go and see what people are building with Avalonia!
 
 
-You can also see what [breaking changes](https://github.com/AvaloniaUI/Avalonia/issues/3538) we have planned and what our [past breaking changes](https://github.com/AvaloniaUI/Avalonia/wiki/Breaking-Changes) have been.
-
-[Awesome Avalonia](https://github.com/AvaloniaCommunity/awesome-avalonia) is community-curated list of awesome Avalonia UI tools, libraries, projects and resources. Go and see what people are building with Avalonia!
-
-## Getting Started
+## 🚀 Getting Started
 
 
 The Avalonia [Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaforVisualStudio) contains project and control templates that will help you get started, or you can use the .NET Core CLI. For a starer guide see our [documentation](http://avaloniaui.net/docs/quickstart/create-new-project).
 The Avalonia [Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaforVisualStudio) contains project and control templates that will help you get started, or you can use the .NET Core CLI. For a starer guide see our [documentation](http://avaloniaui.net/docs/quickstart/create-new-project).
 
 
@@ -30,6 +26,15 @@ Install-Package Avalonia
 Install-Package Avalonia.Desktop
 Install-Package Avalonia.Desktop
 ```
 ```
 
 
+## Showcase
+
+Examples of UIs built with Avalonia
+![image](https://user-images.githubusercontent.com/4672627/84707589-5b69a880-af35-11ea-87a6-7ad57a31d314.png)
+
+![image](https://user-images.githubusercontent.com/4672627/84708576-28281900-af37-11ea-8c88-e29dfcfa0558.png)
+
+![image](https://user-images.githubusercontent.com/4672627/84708947-c3b98980-af37-11ea-8c9d-503334615bbf.png)
+
 ## JetBrains Rider
 ## JetBrains Rider
 
 
 If you need to develop Avalonia app with JetBrains Rider, go and *vote* on [this issue](https://youtrack.jetbrains.com/issue/RIDER-39247) in their tracker. JetBrains won't do things without their users telling them that they want the feature, so only **YOU** can make it happen.
 If you need to develop Avalonia app with JetBrains Rider, go and *vote* on [this issue](https://youtrack.jetbrains.com/issue/RIDER-39247) in their tracker. JetBrains won't do things without their users telling them that they want the feature, so only **YOU** can make it happen.

+ 1 - 1
samples/ControlCatalog/Pages/ToolTipPage.xaml

@@ -18,7 +18,7 @@
                     ToolTip.Tip="This is a ToolTip">
                     ToolTip.Tip="This is a ToolTip">
                 <TextBlock>Hover Here</TextBlock>
                 <TextBlock>Hover Here</TextBlock>
             </Border>
             </Border>
-            <CheckBox Grid.Column="1"
+            <ToggleSwitch Grid.Column="1"
                       Margin="5"
                       Margin="5"
                       Grid.Row="0"
                       Grid.Row="0"
                       IsChecked="{Binding ElementName=Border, Path=(ToolTip.IsOpen)}"
                       IsChecked="{Binding ElementName=Border, Path=(ToolTip.IsOpen)}"

+ 153 - 14
src/Avalonia.Controls/ContextMenu.cs

@@ -1,17 +1,18 @@
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.ComponentModel;
 using System.ComponentModel;
-using System.Linq;
 using Avalonia.Controls.Generators;
 using Avalonia.Controls.Generators;
 using Avalonia.Controls.Platform;
 using Avalonia.Controls.Platform;
 using Avalonia.Controls.Primitives;
 using Avalonia.Controls.Primitives;
+using Avalonia.Controls.Primitives.PopupPositioning;
 using Avalonia.Controls.Templates;
 using Avalonia.Controls.Templates;
 using Avalonia.Input;
 using Avalonia.Input;
 using Avalonia.Interactivity;
 using Avalonia.Interactivity;
 using Avalonia.Layout;
 using Avalonia.Layout;
-using Avalonia.LogicalTree;
 using Avalonia.Styling;
 using Avalonia.Styling;
 
 
+#nullable enable
+
 namespace Avalonia.Controls
 namespace Avalonia.Controls
 {
 {
     /// <summary>
     /// <summary>
@@ -19,11 +20,59 @@ namespace Avalonia.Controls
     /// </summary>
     /// </summary>
     public class ContextMenu : MenuBase, ISetterValue
     public class ContextMenu : MenuBase, ISetterValue
     {
     {
+        /// <summary>
+        /// Defines the <see cref="HorizontalOffset"/> property.
+        /// </summary>
+        public static readonly StyledProperty<double> HorizontalOffsetProperty =
+            Popup.HorizontalOffsetProperty.AddOwner<ContextMenu>();
+
+        /// <summary>
+        /// Defines the <see cref="VerticalOffset"/> property.
+        /// </summary>
+        public static readonly StyledProperty<double> VerticalOffsetProperty =
+            Popup.VerticalOffsetProperty.AddOwner<ContextMenu>();
+
+        /// <summary>
+        /// Defines the <see cref="PlacementAnchor"/> property.
+        /// </summary>
+        public static readonly StyledProperty<PopupAnchor> PlacementAnchorProperty =
+            Popup.PlacementAnchorProperty.AddOwner<ContextMenu>();
+
+        /// <summary>
+        /// Defines the <see cref="PlacementConstraintAdjustment"/> property.
+        /// </summary>
+        public static readonly StyledProperty<PopupPositionerConstraintAdjustment> PlacementConstraintAdjustmentProperty =
+            Popup.PlacementConstraintAdjustmentProperty.AddOwner<ContextMenu>();
+
+        /// <summary>
+        /// Defines the <see cref="PlacementGravity"/> property.
+        /// </summary>
+        public static readonly StyledProperty<PopupGravity> PlacementGravityProperty =
+            Popup.PlacementGravityProperty.AddOwner<ContextMenu>();
+
+        /// <summary>
+        /// Defines the <see cref="PlacementMode"/> property.
+        /// </summary>
+        public static readonly StyledProperty<PlacementMode> PlacementModeProperty =
+            Popup.PlacementModeProperty.AddOwner<ContextMenu>();
+
+        /// <summary>
+        /// Defines the <see cref="PlacementRect"/> property.
+        /// </summary>
+        public static readonly StyledProperty<Rect?> PlacementRectProperty =
+            AvaloniaProperty.Register<Popup, Rect?>(nameof(PlacementRect));
+
+        /// <summary>
+        /// Defines the <see cref="PlacementTarget"/> property.
+        /// </summary>
+        public static readonly StyledProperty<Control?> PlacementTargetProperty =
+            Popup.PlacementTargetProperty.AddOwner<ContextMenu>();
+
         private static readonly ITemplate<IPanel> DefaultPanel =
         private static readonly ITemplate<IPanel> DefaultPanel =
             new FuncTemplate<IPanel>(() => new StackPanel { Orientation = Orientation.Vertical });
             new FuncTemplate<IPanel>(() => new StackPanel { Orientation = Orientation.Vertical });
-        private Popup _popup;
-        private List<Control> _attachedControls;
-        private IInputElement _previousFocus;
+        private Popup? _popup;
+        private List<Control>? _attachedControls;
+        private IInputElement? _previousFocus;
 
 
         /// <summary>
         /// <summary>
         /// Initializes a new instance of the <see cref="ContextMenu"/> class.
         /// Initializes a new instance of the <see cref="ContextMenu"/> class.
@@ -47,23 +96,107 @@ namespace Avalonia.Controls
         /// </summary>
         /// </summary>
         static ContextMenu()
         static ContextMenu()
         {
         {
-            ItemsPanelProperty.OverrideDefaultValue(typeof(ContextMenu), DefaultPanel);
+            ItemsPanelProperty.OverrideDefaultValue<ContextMenu>(DefaultPanel);
+            PlacementModeProperty.OverrideDefaultValue<ContextMenu>(PlacementMode.Pointer);
             ContextMenuProperty.Changed.Subscribe(ContextMenuChanged);
             ContextMenuProperty.Changed.Subscribe(ContextMenuChanged);
         }
         }
 
 
+        /// <summary>
+        /// Gets or sets the Horizontal offset of the context menu in relation to the <see cref="PlacementTarget"/>.
+        /// </summary>
+        public double HorizontalOffset
+        {
+            get { return GetValue(HorizontalOffsetProperty); }
+            set { SetValue(HorizontalOffsetProperty, value); }
+        }
+
+        /// <summary>
+        /// Gets or sets the Vertical offset of the context menu in relation to the <see cref="PlacementTarget"/>.
+        /// </summary>
+        public double VerticalOffset
+        {
+            get { return GetValue(VerticalOffsetProperty); }
+            set { SetValue(VerticalOffsetProperty, value); }
+        }
+
+        /// <summary>
+        /// Gets or sets the anchor point on the <see cref="PlacementRect"/> when <see cref="PlacementMode"/>
+        /// is <see cref="PlacementMode.AnchorAndGravity"/>.
+        /// </summary>
+        public PopupAnchor PlacementAnchor
+        {
+            get { return GetValue(PlacementAnchorProperty); }
+            set { SetValue(PlacementAnchorProperty, value); }
+        }
+
+        /// <summary>
+        /// Gets or sets a value describing how the context menu position will be adjusted if the
+        /// unadjusted position would result in the context menu being partly constrained.
+        /// </summary>
+        public PopupPositionerConstraintAdjustment PlacementConstraintAdjustment
+        {
+            get { return GetValue(PlacementConstraintAdjustmentProperty); }
+            set { SetValue(PlacementConstraintAdjustmentProperty, value); }
+        }
+
+        /// <summary>
+        /// Gets or sets a value which defines in what direction the context menu should open
+        /// when <see cref="PlacementMode"/> is <see cref="PlacementMode.AnchorAndGravity"/>.
+        /// </summary>
+        public PopupGravity PlacementGravity
+        {
+            get { return GetValue(PlacementGravityProperty); }
+            set { SetValue(PlacementGravityProperty, value); }
+        }
+
+        /// <summary>
+        /// Gets or sets the placement mode of the context menu in relation to the<see cref="PlacementTarget"/>.
+        /// </summary>
+        public PlacementMode PlacementMode
+        {
+            get { return GetValue(PlacementModeProperty); }
+            set { SetValue(PlacementModeProperty, value); }
+        }
+
+        /// <summary>
+        /// Gets or sets the the anchor rectangle within the parent that the context menu will be placed
+        /// relative to when <see cref="PlacementMode"/> is <see cref="PlacementMode.AnchorAndGravity"/>.
+        /// </summary>
+        /// <remarks>
+        /// The placement rect defines a rectangle relative to <see cref="PlacementTarget"/> around
+        /// which the popup will be opened, with <see cref="PlacementAnchor"/> determining which edge
+        /// of the placement target is used.
+        /// 
+        /// If unset, the anchor rectangle will be the bounds of the <see cref="PlacementTarget"/>.
+        /// </remarks>
+        public Rect? PlacementRect
+        {
+            get { return GetValue(PlacementRectProperty); }
+            set { SetValue(PlacementRectProperty, value); }
+        }
+
+        /// <summary>
+        /// Gets or sets the control that is used to determine the popup's position.
+        /// </summary>
+        public Control? PlacementTarget
+        {
+            get { return GetValue(PlacementTargetProperty); }
+            set { SetValue(PlacementTargetProperty, value); }
+        }
+
         /// <summary>
         /// <summary>
         /// Occurs when the value of the
         /// Occurs when the value of the
         /// <see cref="P:Avalonia.Controls.ContextMenu.IsOpen" />
         /// <see cref="P:Avalonia.Controls.ContextMenu.IsOpen" />
         /// property is changing from false to true.
         /// property is changing from false to true.
         /// </summary>
         /// </summary>
-        public event CancelEventHandler ContextMenuOpening;
+        public event CancelEventHandler? ContextMenuOpening;
 
 
         /// <summary>
         /// <summary>
         /// Occurs when the value of the
         /// Occurs when the value of the
         /// <see cref="P:Avalonia.Controls.ContextMenu.IsOpen" />
         /// <see cref="P:Avalonia.Controls.ContextMenu.IsOpen" />
         /// property is changing from true to false.
         /// property is changing from true to false.
         /// </summary>
         /// </summary>
-        public event CancelEventHandler ContextMenuClosing;
+        public event CancelEventHandler? ContextMenuClosing;
 
 
         /// <summary>
         /// <summary>
         /// Called when the <see cref="Control.ContextMenu"/> property changes on a control.
         /// Called when the <see cref="Control.ContextMenu"/> property changes on a control.
@@ -77,7 +210,7 @@ namespace Avalonia.Controls
             {
             {
                 control.PointerReleased -= ControlPointerReleased;
                 control.PointerReleased -= ControlPointerReleased;
                 oldMenu._attachedControls?.Remove(control);
                 oldMenu._attachedControls?.Remove(control);
-                ((ISetLogicalParent)oldMenu._popup)?.SetParent(null);
+                ((ISetLogicalParent?)oldMenu._popup)?.SetParent(null);
             }
             }
 
 
             if (e.NewValue is ContextMenu newMenu)
             if (e.NewValue is ContextMenu newMenu)
@@ -97,7 +230,7 @@ namespace Avalonia.Controls
         /// Opens a context menu on the specified control.
         /// Opens a context menu on the specified control.
         /// </summary>
         /// </summary>
         /// <param name="control">The control.</param>
         /// <param name="control">The control.</param>
-        public void Open(Control control)
+        public void Open(Control? control)
         {
         {
             if (control is null && (_attachedControls is null || _attachedControls.Count == 0))
             if (control is null && (_attachedControls is null || _attachedControls.Count == 0))
             {
             {
@@ -113,7 +246,7 @@ namespace Avalonia.Controls
                     nameof(control));
                     nameof(control));
             }
             }
 
 
-            control ??= _attachedControls[0];
+            control ??= _attachedControls![0];
 
 
             if (IsOpen)
             if (IsOpen)
             {
             {
@@ -124,8 +257,14 @@ namespace Avalonia.Controls
             {
             {
                 _popup = new Popup
                 _popup = new Popup
                 {
                 {
-                    PlacementMode = PlacementMode.Pointer,
-                    PlacementTarget = control,
+                    HorizontalOffset = HorizontalOffset,
+                    VerticalOffset = VerticalOffset,
+                    PlacementAnchor = PlacementAnchor,
+                    PlacementConstraintAdjustment = PlacementConstraintAdjustment,
+                    PlacementGravity = PlacementGravity,
+                    PlacementMode = PlacementMode,
+                    PlacementRect = PlacementRect,
+                    PlacementTarget = PlacementTarget ?? control,
                     StaysOpen = false
                     StaysOpen = false
                 };
                 };
 
 
@@ -204,7 +343,7 @@ namespace Avalonia.Controls
 
 
             if (_attachedControls is null || _attachedControls.Count == 0)
             if (_attachedControls is null || _attachedControls.Count == 0)
             {
             {
-                ((ISetLogicalParent)_popup).SetParent(null);
+                ((ISetLogicalParent)_popup!).SetParent(null);
             }
             }
 
 
             // HACK: Reset the focus when the popup is closed. We need to fix this so it's automatic.
             // HACK: Reset the focus when the popup is closed. We need to fix this so it's automatic.

+ 5 - 0
src/Avalonia.Controls/MenuItem.cs

@@ -105,6 +105,7 @@ namespace Avalonia.Controls
         static MenuItem()
         static MenuItem()
         {
         {
             SelectableMixin.Attach<MenuItem>(IsSelectedProperty);
             SelectableMixin.Attach<MenuItem>(IsSelectedProperty);
+            PressedMixin.Attach<MenuItem>();
             CommandProperty.Changed.Subscribe(CommandChanged);
             CommandProperty.Changed.Subscribe(CommandChanged);
             FocusableProperty.OverrideDefaultValue<MenuItem>(true);
             FocusableProperty.OverrideDefaultValue<MenuItem>(true);
             HeaderProperty.Changed.AddClassHandler<MenuItem>((x, e) => x.HeaderChanged(e));
             HeaderProperty.Changed.AddClassHandler<MenuItem>((x, e) => x.HeaderChanged(e));
@@ -534,11 +535,13 @@ namespace Avalonia.Controls
             if (oldValue != null)
             if (oldValue != null)
             {
             {
                 LogicalChildren.Remove(oldValue);
                 LogicalChildren.Remove(oldValue);
+                PseudoClasses.Remove(":icon");
             }
             }
 
 
             if (newValue != null)
             if (newValue != null)
             {
             {
                 LogicalChildren.Add(newValue);
                 LogicalChildren.Add(newValue);
+                PseudoClasses.Add(":icon");
             }
             }
         }
         }
 
 
@@ -566,11 +569,13 @@ namespace Avalonia.Controls
             {
             {
                 RaiseEvent(new RoutedEventArgs(SubmenuOpenedEvent));
                 RaiseEvent(new RoutedEventArgs(SubmenuOpenedEvent));
                 IsSelected = true;
                 IsSelected = true;
+                PseudoClasses.Add(":open");
             }
             }
             else
             else
             {
             {
                 CloseSubmenus();
                 CloseSubmenus();
                 SelectedIndex = -1;
                 SelectedIndex = -1;
+                PseudoClasses.Remove(":open");
             }
             }
         }
         }
 
 

+ 53 - 2
src/Avalonia.Controls/Primitives/IPopupHost.cs

@@ -5,19 +5,70 @@ using Avalonia.VisualTree;
 
 
 namespace Avalonia.Controls.Primitives
 namespace Avalonia.Controls.Primitives
 {
 {
+    /// <summary>
+    /// Represents the top-level control opened by a <see cref="Popup"/>.
+    /// </summary>
+    /// <remarks>
+    /// A popup host can be either be a popup window created by the operating system
+    /// (<see cref="PopupRoot"/>) or an <see cref="OverlayPopupHost"/> which is created
+    /// on an <see cref="OverlayLayer"/>.
+    /// </remarks>
     public interface IPopupHost : IDisposable
     public interface IPopupHost : IDisposable
     {
     {
+        /// <summary>
+        /// Sets the control to display in the popup.
+        /// </summary>
+        /// <param name="control"></param>
         void SetChild(IControl control);
         void SetChild(IControl control);
+
+        /// <summary>
+        /// Gets the presenter from the control's template.
+        /// </summary>
         IContentPresenter Presenter { get; }
         IContentPresenter Presenter { get; }
+
+        /// <summary>
+        /// Gets the root of the visual tree in the case where the popup is presented using a
+        /// separate visual tree.
+        /// </summary>
         IVisual HostedVisualTreeRoot { get; }
         IVisual HostedVisualTreeRoot { get; }
 
 
+        /// <summary>
+        /// Raised when the control's template is applied.
+        /// </summary>
         event EventHandler<TemplateAppliedEventArgs> TemplateApplied;
         event EventHandler<TemplateAppliedEventArgs> TemplateApplied;
 
 
+        /// <summary>
+        /// Configures the position of the popup according to a target control and a set of
+        /// placement parameters.
+        /// </summary>
+        /// <param name="target">The placement target.</param>
+        /// <param name="placement">The placement mode.</param>
+        /// <param name="offset">The offset, in device-independent pixels.</param>
+        /// <param name="anchor">The anchor point.</param>
+        /// <param name="gravity">The popup gravity.</param>
+        /// <param name="rect">
+        /// The anchor rect. If null, the bounds of <paramref name="target"/> will be used.
+        /// </param>
         void ConfigurePosition(IVisual target, PlacementMode placement, Point offset,
         void ConfigurePosition(IVisual target, PlacementMode placement, Point offset,
-            PopupPositioningEdge anchor = PopupPositioningEdge.None,
-            PopupPositioningEdge gravity = PopupPositioningEdge.None);
+            PopupAnchor anchor = PopupAnchor.None,
+            PopupGravity gravity = PopupGravity.None,
+            PopupPositionerConstraintAdjustment constraintAdjustment = PopupPositionerConstraintAdjustment.All,
+            Rect? rect = null);
+
+        /// <summary>
+        /// Shows the popup.
+        /// </summary>
         void Show();
         void Show();
+
+        /// <summary>
+        /// Hides the popup.
+        /// </summary>
         void Hide();
         void Hide();
+
+        /// <summary>
+        /// Binds the constraints of the popup host to a set of properties, usally those present on
+        /// <see cref="Popup"/>.
+        /// </summary>
         IDisposable BindConstraints(AvaloniaObject popup, StyledProperty<double> widthProperty,
         IDisposable BindConstraints(AvaloniaObject popup, StyledProperty<double> widthProperty,
             StyledProperty<double> minWidthProperty, StyledProperty<double> maxWidthProperty,
             StyledProperty<double> minWidthProperty, StyledProperty<double> maxWidthProperty,
             StyledProperty<double> heightProperty, StyledProperty<double> minHeightProperty,
             StyledProperty<double> heightProperty, StyledProperty<double> minHeightProperty,

+ 6 - 6
src/Avalonia.Controls/Primitives/OverlayPopupHost.cs

@@ -71,10 +71,12 @@ namespace Avalonia.Controls.Primitives
         }
         }
 
 
         public void ConfigurePosition(IVisual target, PlacementMode placement, Point offset,
         public void ConfigurePosition(IVisual target, PlacementMode placement, Point offset,
-            PopupPositioningEdge anchor = PopupPositioningEdge.None, PopupPositioningEdge gravity = PopupPositioningEdge.None)
+            PopupAnchor anchor = PopupAnchor.None, PopupGravity gravity = PopupGravity.None,
+            PopupPositionerConstraintAdjustment constraintAdjustment = PopupPositionerConstraintAdjustment.All,
+            Rect? rect = null)
         {
         {
             _positionerParameters.ConfigurePosition((TopLevel)_overlayLayer.GetVisualRoot(), target, placement, offset, anchor,
             _positionerParameters.ConfigurePosition((TopLevel)_overlayLayer.GetVisualRoot(), target, placement, offset, anchor,
-                gravity);
+                gravity, constraintAdjustment, rect);
             UpdatePosition();
             UpdatePosition();
         }
         }
 
 
@@ -122,10 +124,8 @@ namespace Avalonia.Controls.Primitives
             }, DispatcherPriority.Layout);
             }, DispatcherPriority.Layout);
         }
         }
 
 
-        Point IManagedPopupPositionerPopup.TranslatePoint(Point pt) => pt;
-
-        Size IManagedPopupPositionerPopup.TranslateSize(Size size) => size;
-        
+        double IManagedPopupPositionerPopup.Scaling => 1;
+       
         public static IPopupHost CreatePopupHost(IVisual target, IAvaloniaDependencyResolver dependencyResolver)
         public static IPopupHost CreatePopupHost(IVisual target, IAvaloniaDependencyResolver dependencyResolver)
         {
         {
             var platform = (target.GetVisualRoot() as TopLevel)?.PlatformImpl?.CreatePopup();
             var platform = (target.GetVisualRoot() as TopLevel)?.PlatformImpl?.CreatePopup();

+ 98 - 19
src/Avalonia.Controls/Primitives/Popup.cs

@@ -3,6 +3,7 @@ using System.Diagnostics;
 using System.Linq;
 using System.Linq;
 using System.Reactive.Disposables;
 using System.Reactive.Disposables;
 using Avalonia.Controls.Presenters;
 using Avalonia.Controls.Presenters;
+using Avalonia.Controls.Primitives.PopupPositioning;
 using Avalonia.Input;
 using Avalonia.Input;
 using Avalonia.Input.Raw;
 using Avalonia.Input.Raw;
 using Avalonia.Interactivity;
 using Avalonia.Interactivity;
@@ -37,12 +38,45 @@ namespace Avalonia.Controls.Primitives
                 o => o.IsOpen,
                 o => o.IsOpen,
                 (o, v) => o.IsOpen = v);
                 (o, v) => o.IsOpen = v);
 
 
+        /// <summary>
+        /// Defines the <see cref="PlacementAnchor"/> property.
+        /// </summary>
+        public static readonly StyledProperty<PopupAnchor> PlacementAnchorProperty =
+            AvaloniaProperty.Register<Popup, PopupAnchor>(nameof(PlacementAnchor));
+
+        /// <summary>
+        /// Defines the <see cref="PlacementConstraintAdjustment"/> property.
+        /// </summary>
+        public static readonly StyledProperty<PopupPositionerConstraintAdjustment> PlacementConstraintAdjustmentProperty =
+            AvaloniaProperty.Register<Popup, PopupPositionerConstraintAdjustment>(
+                nameof(PlacementConstraintAdjustment),
+                PopupPositionerConstraintAdjustment.FlipX | PopupPositionerConstraintAdjustment.FlipY |
+                PopupPositionerConstraintAdjustment.ResizeX | PopupPositionerConstraintAdjustment.ResizeY);
+
+        /// <summary>
+        /// Defines the <see cref="PlacementGravity"/> property.
+        /// </summary>
+        public static readonly StyledProperty<PopupGravity> PlacementGravityProperty =
+            AvaloniaProperty.Register<Popup, PopupGravity>(nameof(PlacementGravity));
+
         /// <summary>
         /// <summary>
         /// Defines the <see cref="PlacementMode"/> property.
         /// Defines the <see cref="PlacementMode"/> property.
         /// </summary>
         /// </summary>
         public static readonly StyledProperty<PlacementMode> PlacementModeProperty =
         public static readonly StyledProperty<PlacementMode> PlacementModeProperty =
             AvaloniaProperty.Register<Popup, PlacementMode>(nameof(PlacementMode), defaultValue: PlacementMode.Bottom);
             AvaloniaProperty.Register<Popup, PlacementMode>(nameof(PlacementMode), defaultValue: PlacementMode.Bottom);
 
 
+        /// <summary>
+        /// Defines the <see cref="PlacementRect"/> property.
+        /// </summary>
+        public static readonly StyledProperty<Rect?> PlacementRectProperty =
+            AvaloniaProperty.Register<Popup, Rect?>(nameof(PlacementRect));
+
+        /// <summary>
+        /// Defines the <see cref="PlacementTarget"/> property.
+        /// </summary>
+        public static readonly StyledProperty<Control?> PlacementTargetProperty =
+            AvaloniaProperty.Register<Popup, Control?>(nameof(PlacementTarget));
+
 #pragma warning disable 618
 #pragma warning disable 618
         /// <summary>
         /// <summary>
         /// Defines the <see cref="ObeyScreenEdges"/> property.
         /// Defines the <see cref="ObeyScreenEdges"/> property.
@@ -63,12 +97,6 @@ namespace Avalonia.Controls.Primitives
         public static readonly StyledProperty<double> VerticalOffsetProperty =
         public static readonly StyledProperty<double> VerticalOffsetProperty =
             AvaloniaProperty.Register<Popup, double>(nameof(VerticalOffset));
             AvaloniaProperty.Register<Popup, double>(nameof(VerticalOffset));
 
 
-        /// <summary>
-        /// Defines the <see cref="PlacementTarget"/> property.
-        /// </summary>
-        public static readonly StyledProperty<Control?> PlacementTargetProperty =
-            AvaloniaProperty.Register<Popup, Control?>(nameof(PlacementTarget));
-
         /// <summary>
         /// <summary>
         /// Defines the <see cref="StaysOpen"/> property.
         /// Defines the <see cref="StaysOpen"/> property.
         /// </summary>
         /// </summary>
@@ -145,6 +173,36 @@ namespace Avalonia.Controls.Primitives
             set { SetAndRaise(IsOpenProperty, ref _isOpen, value); }
             set { SetAndRaise(IsOpenProperty, ref _isOpen, value); }
         }
         }
 
 
+        /// <summary>
+        /// Gets or sets the anchor point on the <see cref="PlacementRect"/> when <see cref="PlacementMode"/>
+        /// is <see cref="PlacementMode.AnchorAndGravity"/>.
+        /// </summary>
+        public PopupAnchor PlacementAnchor
+        {
+            get { return GetValue(PlacementAnchorProperty); }
+            set { SetValue(PlacementAnchorProperty, value); }
+        }
+
+        /// <summary>
+        /// Gets or sets a value describing how the popup position will be adjusted if the
+        /// unadjusted position would result in the popup being partly constrained.
+        /// </summary>
+        public PopupPositionerConstraintAdjustment PlacementConstraintAdjustment
+        {
+            get { return GetValue(PlacementConstraintAdjustmentProperty); }
+            set { SetValue(PlacementConstraintAdjustmentProperty, value); }
+        }
+
+        /// <summary>
+        /// Gets or sets a value which defines in what direction the popup should open
+        /// when <see cref="PlacementMode"/> is <see cref="PlacementMode.AnchorAndGravity"/>.
+        /// </summary>
+        public PopupGravity PlacementGravity
+        {
+            get { return GetValue(PlacementGravityProperty); }
+            set { SetValue(PlacementGravityProperty, value); }
+        }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the placement mode of the popup in relation to the <see cref="PlacementTarget"/>.
         /// Gets or sets the placement mode of the popup in relation to the <see cref="PlacementTarget"/>.
         /// </summary>
         /// </summary>
@@ -154,6 +212,32 @@ namespace Avalonia.Controls.Primitives
             set { SetValue(PlacementModeProperty, value); }
             set { SetValue(PlacementModeProperty, value); }
         }
         }
 
 
+        /// <summary>
+        /// Gets or sets the the anchor rectangle within the parent that the popup will be placed
+        /// relative to when <see cref="PlacementMode"/> is <see cref="PlacementMode.AnchorAndGravity"/>.
+        /// </summary>
+        /// <remarks>
+        /// The placement rect defines a rectangle relative to <see cref="PlacementTarget"/> around
+        /// which the popup will be opened, with <see cref="PlacementAnchor"/> determining which edge
+        /// of the placement target is used.
+        /// 
+        /// If unset, the anchor rectangle will be the bounds of the <see cref="PlacementTarget"/>.
+        /// </remarks>
+        public Rect? PlacementRect
+        {
+            get { return GetValue(PlacementRectProperty); }
+            set { SetValue(PlacementRectProperty, value); }
+        }
+
+        /// <summary>
+        /// Gets or sets the control that is used to determine the popup's position.
+        /// </summary>
+        public Control? PlacementTarget
+        {
+            get { return GetValue(PlacementTargetProperty); }
+            set { SetValue(PlacementTargetProperty, value); }
+        }
+
         [Obsolete("This property has no effect")]
         [Obsolete("This property has no effect")]
         public bool ObeyScreenEdges
         public bool ObeyScreenEdges
         {
         {
@@ -162,7 +246,7 @@ namespace Avalonia.Controls.Primitives
         }
         }
 
 
         /// <summary>
         /// <summary>
-        /// Gets or sets the Horizontal offset of the popup in relation to the <see cref="PlacementTarget"/>
+        /// Gets or sets the Horizontal offset of the popup in relation to the <see cref="PlacementTarget"/>.
         /// </summary>
         /// </summary>
         public double HorizontalOffset
         public double HorizontalOffset
         {
         {
@@ -171,7 +255,7 @@ namespace Avalonia.Controls.Primitives
         }
         }
 
 
         /// <summary>
         /// <summary>
-        /// Gets or sets the Vertical offset of the popup in relation to the <see cref="PlacementTarget"/>
+        /// Gets or sets the Vertical offset of the popup in relation to the <see cref="PlacementTarget"/>.
         /// </summary>
         /// </summary>
         public double VerticalOffset
         public double VerticalOffset
         {
         {
@@ -179,15 +263,6 @@ namespace Avalonia.Controls.Primitives
             set { SetValue(VerticalOffsetProperty, value); }
             set { SetValue(VerticalOffsetProperty, value); }
         }
         }
 
 
-        /// <summary>
-        /// Gets or sets the control that is used to determine the popup's position.
-        /// </summary>
-        public Control? PlacementTarget
-        {
-            get { return GetValue(PlacementTargetProperty); }
-            set { SetValue(PlacementTargetProperty, value); }
-        }
-
         /// <summary>
         /// <summary>
         /// Gets or sets a value indicating whether the popup should stay open when the popup is
         /// Gets or sets a value indicating whether the popup should stay open when the popup is
         /// pressed or loses focus.
         /// pressed or loses focus.
@@ -260,8 +335,12 @@ namespace Avalonia.Controls.Primitives
 
 
             popupHost.ConfigurePosition(
             popupHost.ConfigurePosition(
                 placementTarget,
                 placementTarget,
-                PlacementMode, 
-                new Point(HorizontalOffset, VerticalOffset));
+                PlacementMode,
+                new Point(HorizontalOffset, VerticalOffset),
+                PlacementAnchor,
+                PlacementGravity,
+                PlacementConstraintAdjustment,
+                PlacementRect);
 
 
             DeferCleanup(SubscribeToEventHandler<IPopupHost, EventHandler<TemplateAppliedEventArgs>>(popupHost, RootTemplateApplied,
             DeferCleanup(SubscribeToEventHandler<IPopupHost, EventHandler<TemplateAppliedEventArgs>>(popupHost, RootTemplateApplied,
                 (x, handler) => x.TemplateApplied += handler,
                 (x, handler) => x.TemplateApplied += handler,

+ 287 - 137
src/Avalonia.Controls/Primitives/PopupPositioning/IPopupPositioner.cs

@@ -50,46 +50,48 @@ using Avalonia.VisualTree;
 namespace Avalonia.Controls.Primitives.PopupPositioning
 namespace Avalonia.Controls.Primitives.PopupPositioning
 {
 {
     /// <summary>
     /// <summary>
-    /// 
-    /// The IPopupPositioner provides a collection of rules for the placement of a
-    /// a popup relative to its parent. Rules can be defined to ensure
-    /// the popup remains within the visible area's borders, and to
-    /// specify how the popup changes its position, such as sliding along
-    /// an axis, or flipping around a rectangle. These positioner-created rules are
-    /// constrained by the requirement that a popup must intersect with or
-    /// be at least partially adjacent to its parent surface.
+    /// Provides positioning parameters to <see cref="IPopupPositioner"/>.
     /// </summary>
     /// </summary>
+    /// <remarks>
+    /// The IPopupPositioner provides a collection of rules for the placement of a a popup relative
+    /// to its parent. Rules can be defined to ensure the popup remains within the visible area's
+    /// borders, and to specify how the popup changes its position, such as sliding along an axis,
+    /// or flipping around a rectangle. These positioner-created rules are constrained by the
+    /// requirement that a popup must intersect with or be at least partially adjacent to its parent
+    /// surface.
+    /// </remarks>
     public struct PopupPositionerParameters
     public struct PopupPositionerParameters
     {
     {
-        private PopupPositioningEdge _gravity;
-        private PopupPositioningEdge _anchor;
+        private PopupGravity _gravity;
+        private PopupAnchor _anchor;
 
 
         /// <summary>
         /// <summary>
-        /// Set the size of the popup that is to be positioned with the positioner
-        /// object. The size is in scaled coordinates.
+        /// Set the size of the popup that is to be positioned with the positioner object, in device-
+        /// independent pixels.
         /// </summary>
         /// </summary>
         public Size Size { get; set; }
         public Size Size { get; set; }
 
 
         /// <summary>
         /// <summary>
-        /// Specify the anchor rectangle within the parent that the popup
-        /// will be placed relative to. The rectangle is relative to the
-        /// parent geometry
-        /// 
-        /// The anchor rectangle may not extend outside the window geometry of the
-        /// popup's parent. The anchor rectangle is in scaled coordinates
+        /// Specifies the anchor rectangle within the parent that the popup will be placed relative
+        /// to, in device-independent pixels.
         /// </summary>
         /// </summary>
+        /// <remarks>
+        /// The rectangle is relative to the parent geometry and may not extend outside the window
+        /// geometry of the popup's parent.
+        /// </remarks>
         public Rect AnchorRectangle { get; set; }
         public Rect AnchorRectangle { get; set; }
 
 
-
         /// <summary>
         /// <summary>
-        /// Defines the anchor point for the anchor rectangle. The specified anchor
-        /// is used derive an anchor point that the popup will be
-        /// positioned relative to. If a corner anchor is set (e.g. 'TopLeft' or
-        /// 'BottomRight'), the anchor point will be at the specified corner;
-        /// otherwise, the derived anchor point will be centered on the specified
-        /// edge, or in the center of the anchor rectangle if no edge is specified.
+        /// Defines the anchor point for the anchor rectangle.
         /// </summary>
         /// </summary>
-        public PopupPositioningEdge Anchor
+        /// <remarks>
+        /// The specified anchor is used derive an anchor point that the popup will be positioned
+        /// relative to. If a corner anchor is set (e.g. 'TopLeft' or 'BottomRight'), the anchor
+        /// point will be at the specified corner; otherwise, the derived anchor point will be
+        /// centered on the specified edge, or in the center of the anchor rectangle if no edge is
+        /// specified.
+        /// </remarks>
+        public PopupAnchor Anchor
         {
         {
             get => _anchor;
             get => _anchor;
             set
             set
@@ -100,66 +102,70 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
         }
         }
 
 
         /// <summary>
         /// <summary>
-        /// Defines in what direction a popup should be positioned, relative to
-        /// the anchor point of the parent. If a corner gravity is
-        /// specified (e.g. 'BottomRight' or 'TopLeft'), then the popup
-        /// will be placed towards the specified gravity; otherwise, the popup
-        /// will be centered over the anchor point on any axis that had no
-        /// gravity specified.
+        /// Defines in what direction a popup should be positioned, relative to the anchor point of
+        /// the parent.
         /// </summary>
         /// </summary>
-        public PopupPositioningEdge Gravity
+        /// <remarks>
+        /// If a corner gravity is specified (e.g. 'BottomRight' or 'TopLeft'), then the popup will
+        /// be placed towards the specified gravity; otherwise, the popup will be centered over the
+        /// anchor point on any axis that had no gravity specified.
+        /// </remarks>
+        public PopupGravity Gravity
         {
         {
             get => _gravity;
             get => _gravity;
             set
             set
             {
             {
-                PopupPositioningEdgeHelper.ValidateEdge(value);
+                PopupPositioningEdgeHelper.ValidateGravity(value);
                 _gravity = value;
                 _gravity = value;
             }
             }
         }
         }
 
 
         /// <summary>
         /// <summary>
-        /// Specify how the popup should be positioned if the originally intended
-        /// position caused the popup to be constrained, meaning at least
-        /// partially outside positioning boundaries set by the positioner. The
-        /// adjustment is set by constructing a bitmask describing the adjustment to
-        /// be made when the popup is constrained on that axis.
+        /// Specify how the popup should be positioned if the originally intended position caused
+        /// the popup to be constrained.
+        /// </summary>
+        /// <remarks>
+        /// Adjusts the popup position if the intended position caused the popup to be constrained;
+        /// meaning at least partially outside positioning boundaries set by the positioner. The
+        /// adjustment is set by constructing a bitmask describing the adjustment to be made when
+        /// the popup is constrained on that axis.
         /// 
         /// 
-        /// If no bit for one axis is set, the positioner will assume that the child
-        /// surface should not change its position on that axis when constrained.
+        /// If no bit for one axis is set, the positioner will assume that the child surface should
+        /// not change its position on that axis when constrained.
         /// 
         /// 
-        /// If more than one bit for one axis is set, the order of how adjustments
-        /// are applied is specified in the corresponding adjustment descriptions.
+        /// If more than one bit for one axis is set, the order of how adjustments are applied is
+        /// specified in the corresponding adjustment descriptions.
         /// 
         /// 
         /// The default adjustment is none.
         /// The default adjustment is none.
-        /// </summary>
+        /// </remarks>
         public PopupPositionerConstraintAdjustment ConstraintAdjustment { get; set; }
         public PopupPositionerConstraintAdjustment ConstraintAdjustment { get; set; }
-        
+
         /// <summary>
         /// <summary>
         /// Specify the popup position offset relative to the position of the
         /// Specify the popup position offset relative to the position of the
-        /// anchor on the anchor rectangle and the anchor on the popup. For
-        /// example if the anchor of the anchor rectangle is at (x, y), the popup
-        /// has the gravity bottom|right, and the offset is (ox, oy), the calculated
-        /// surface position will be (x + ox, y + oy). The offset position of the
-        /// surface is the one used for constraint testing. See
-        /// set_constraint_adjustment.
-        /// 
-        /// An example use case is placing a popup menu on top of a user interface
-        /// element, while aligning the user interface element of the parent surface
-        /// with some user interface element placed somewhere in the popup.
+        /// anchor on the anchor rectangle and the anchor on the popup.
         /// </summary>
         /// </summary>
+        /// <remarks>
+        /// For example if the anchor of the anchor rectangle is at (x, y), the popup has the
+        /// gravity bottom|right, and the offset is (ox, oy), the calculated surface position will
+        /// be (x + ox, y + oy). The offset position of the surface is the one used for constraint
+        /// testing. See set_constraint_adjustment.
+        /// 
+        /// An example use case is placing a popup menu on top of a user interface element, while
+        /// aligning the user interface element of the parent surface with some user interface
+        /// element placed somewhere in the popup.
+        /// </remarks>
         public Point Offset { get; set; }
         public Point Offset { get; set; }
     }
     }
-    
+
     /// <summary>
     /// <summary>
-    /// The constraint adjustment value define ways how popup position will
-    /// be adjusted if the unadjusted position would result in the popup
-    /// being partly constrained.
-    /// 
-    /// Whether a popup is considered 'constrained' is left to the positioner
-    /// to determine. For example, the popup may be partly outside the
-    /// target platform defined 'work area', thus necessitating the popup's
-    /// position be adjusted until it is entirely inside the work area.
+    /// Defines how a popup position will be adjusted if the unadjusted position would result in
+    /// the popup being partly constrained.
     /// </summary>
     /// </summary>
+    /// <remarks>
+    /// Whether a popup is considered 'constrained' is left to the positioner to determine. For
+    /// example, the popup may be partly outside the target platform defined 'work area', thus
+    /// necessitating the popup's position be adjusted until it is entirely inside the work area.
+    /// </remarks>
     [Flags]
     [Flags]
     public enum PopupPositionerConstraintAdjustment
     public enum PopupPositionerConstraintAdjustment
     {
     {
@@ -171,79 +177,97 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
 
 
         /// <summary>
         /// <summary>
         /// Slide the surface along the x axis until it is no longer constrained.
         /// Slide the surface along the x axis until it is no longer constrained.
-        ///        First try to slide towards the direction of the gravity on the x axis
-        ///        until either the edge in the opposite direction of the gravity is
-        ///        unconstrained or the edge in the direction of the gravity is
-        ///        constrained.
-        ///
-        ///        Then try to slide towards the opposite direction of the gravity on the
-        ///        x axis until either the edge in the direction of the gravity is
-        ///        unconstrained or the edge in the opposite direction of the gravity is
-        ///        constrained.
         /// </summary>
         /// </summary>
+        /// <remarks>
+        /// First try to slide towards the direction of the gravity on the x axis until either the
+        /// edge in the opposite direction of the gravity is unconstrained or the edge in the
+        /// direction of the gravity is constrained.
+        ///
+        /// Then try to slide towards the opposite direction of the gravity on the x axis until
+        /// either the edge in the direction of the gravity is unconstrained or the edge in the
+        /// opposite direction of the gravity is constrained.
+        /// </remarks>
         SlideX = 1,
         SlideX = 1,
 
 
-
         /// <summary>
         /// <summary>
-        ///            Slide the surface along the y axis until it is no longer constrained.
-        /// 
-        /// First try to slide towards the direction of the gravity on the y axis
-        /// until either the edge in the opposite direction of the gravity is
-        /// unconstrained or the edge in the direction of the gravity is
-        /// constrained.
-        /// 
-        /// Then try to slide towards the opposite direction of the gravity on the
-        /// y axis until either the edge in the direction of the gravity is
-        /// unconstrained or the edge in the opposite direction of the gravity is
-        /// constrained.
-        /// */
+        /// Slide the surface along the y axis until it is no longer constrained.
         /// </summary>
         /// </summary>
+        /// <remarks>
+        /// First try to slide towards the direction of the gravity on the y axis until either the
+        /// edge in the opposite direction of the gravity is unconstrained or the edge in the
+        /// direction of the gravity is constrained.
+        /// 
+        /// Then try to slide towards the opposite direction of the gravity on the y axis until
+        /// either the edge in the direction of the gravity is unconstrained or the edge in the
+        /// opposite direction of the gravity is constrained.
+        /// </remarks>
         SlideY = 2,
         SlideY = 2,
 
 
         /// <summary>
         /// <summary>
-        /// Invert the anchor and gravity on the x axis if the surface is
-        /// constrained on the x axis. For example, if the left edge of the
-        /// surface is constrained, the gravity is 'left' and the anchor is
-        /// 'left', change the gravity to 'right' and the anchor to 'right'.
-        /// 
-        /// If the adjusted position also ends up being constrained, the resulting
-        /// position of the flip_x adjustment will be the one before the
-        /// adjustment.
+        /// Invert the anchor and gravity on the x axis if the surface is constrained on the x axis.
         /// </summary>
         /// </summary>
+        /// <remarks>
+        /// For example, if the left edge of the surface is constrained, the gravity is 'left' and
+        /// the anchor is 'left', change the gravity to 'right' and the anchor to 'right'.
+        /// 
+        /// If the adjusted position also ends up being constrained, the resulting position of the
+        /// FlipX adjustment will be the one before the adjustment.
+        /// /// </remarks>
         FlipX = 4,
         FlipX = 4,
 
 
         /// <summary>
         /// <summary>
-        /// Invert the anchor and gravity on the y axis if the surface is
-        /// constrained on the y axis. For example, if the bottom edge of the
-        /// surface is constrained, the gravity is 'bottom' and the anchor is
-        /// 'bottom', change the gravity to 'top' and the anchor to 'top'.
+        /// Invert the anchor and gravity on the y axis if the surface is constrained on the y axis.
+        /// </summary>
+        /// <remarks>
+        /// For example, if the bottom edge of the surface is constrained, the gravity is 'bottom'
+        /// and the anchor is 'bottom', change the gravity to 'top' and the anchor to 'top'.
         /// 
         /// 
-        /// The adjusted position is calculated given the original anchor
-        /// rectangle and offset, but with the new flipped anchor and gravity
-        /// values.
+        /// The adjusted position is calculated given the original anchor rectangle and offset, but
+        /// with the new flipped anchor and gravity values.
         /// 
         /// 
-        /// If the adjusted position also ends up being constrained, the resulting
-        /// position of the flip_y adjustment will be the one before the
-        /// adjustment.
-        /// </summary>
+        /// If the adjusted position also ends up being constrained, the resulting position of the
+        /// FlipY adjustment will be the one before the adjustment.
+        /// </remarks>
         FlipY = 8,
         FlipY = 8,
-        All = SlideX|SlideY|FlipX|FlipY
+
+        /// <summary>
+        /// Horizontally resize the surface
+        /// </summary>
+        /// <remarks>
+        /// Resize the surface horizontally so that it is completely unconstrained.
+        /// </remarks>
+        ResizeX = 16,
+
+        /// <summary>
+        /// Vertically resize the surface
+        /// </summary>
+        /// <remarks>
+        /// Resize the surface vertically so that it is completely unconstrained.
+        /// </remarks>
+        ResizeY = 16,
+
+        All = SlideX|SlideY|FlipX|FlipY|ResizeX|ResizeY
     }
     }
 
 
     static class PopupPositioningEdgeHelper
     static class PopupPositioningEdgeHelper
     {
     {
-        public static void ValidateEdge(this PopupPositioningEdge edge)
+        public static void ValidateEdge(this PopupAnchor edge)
         {
         {
-            if (((edge & PopupPositioningEdge.Left) != 0 && (edge & PopupPositioningEdge.Right) != 0)
+            if (((edge & PopupAnchor.Left) != 0 && (edge & PopupAnchor.Right) != 0)
                 ||
                 ||
-                ((edge & PopupPositioningEdge.Top) != 0 && (edge & PopupPositioningEdge.Bottom) != 0))
+                ((edge & PopupAnchor.Top) != 0 && (edge & PopupAnchor.Bottom) != 0))
                 throw new ArgumentException("Opposite edges specified");
                 throw new ArgumentException("Opposite edges specified");
         }
         }
 
 
-        public static PopupPositioningEdge Flip(this PopupPositioningEdge edge)
+        public static void ValidateGravity(this PopupGravity gravity)
+        {
+            ValidateEdge((PopupAnchor)gravity);
+        }
+
+        public static PopupAnchor Flip(this PopupAnchor edge)
         {
         {
-            var hmask = PopupPositioningEdge.Left | PopupPositioningEdge.Right;
-            var vmask = PopupPositioningEdge.Top | PopupPositioningEdge.Bottom;
+            var hmask = PopupAnchor.Left | PopupAnchor.Right;
+            var vmask = PopupAnchor.Top | PopupAnchor.Bottom;
             if ((edge & hmask) != 0)
             if ((edge & hmask) != 0)
                 edge ^= hmask;
                 edge ^= hmask;
             if ((edge & vmask) != 0)
             if ((edge & vmask) != 0)
@@ -251,43 +275,167 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
             return edge;
             return edge;
         }
         }
 
 
-        public static PopupPositioningEdge FlipX(this PopupPositioningEdge edge)
+        public static PopupAnchor FlipX(this PopupAnchor edge)
         {
         {
-            if ((edge & PopupPositioningEdge.HorizontalMask) != 0)
-                edge ^= PopupPositioningEdge.HorizontalMask;
+            if ((edge & PopupAnchor.HorizontalMask) != 0)
+                edge ^= PopupAnchor.HorizontalMask;
             return edge;
             return edge;
         }
         }
         
         
-        public static PopupPositioningEdge FlipY(this PopupPositioningEdge edge)
+        public static PopupAnchor FlipY(this PopupAnchor edge)
         {
         {
-            if ((edge & PopupPositioningEdge.VerticalMask) != 0)
-                edge ^= PopupPositioningEdge.VerticalMask;
+            if ((edge & PopupAnchor.VerticalMask) != 0)
+                edge ^= PopupAnchor.VerticalMask;
             return edge;
             return edge;
         }
         }
-        
+
+        public static PopupGravity FlipX(this PopupGravity gravity)
+        {
+            return (PopupGravity)FlipX((PopupAnchor)gravity);
+        }
+
+        public static PopupGravity FlipY(this PopupGravity gravity)
+        {
+            return (PopupGravity)FlipY((PopupAnchor)gravity);
+        }
     }
     }
 
 
+    /// <summary>
+    /// Defines the edges around an anchor rectangle on which a popup will open.
+    /// </summary>
     [Flags]
     [Flags]
-    public enum PopupPositioningEdge
+    public enum PopupAnchor
     {
     {
+        /// <summary>
+        /// The center of the anchor rectangle.
+        /// </summary>
         None,
         None,
+
+        /// <summary>
+        /// The top edge of the anchor rectangle.
+        /// </summary>
         Top = 1,
         Top = 1,
+
+        /// <summary>
+        /// The bottom edge of the anchor rectangle.
+        /// </summary>
         Bottom = 2,
         Bottom = 2,
+
+        /// <summary>
+        /// The left edge of the anchor rectangle.
+        /// </summary>
         Left = 4,
         Left = 4,
+
+        /// <summary>
+        /// The right edge of the anchor rectangle.
+        /// </summary>
         Right = 8,
         Right = 8,
+
+        /// <summary>
+        /// The top-left corner of the anchor rectangle.
+        /// </summary>
         TopLeft = Top | Left,
         TopLeft = Top | Left,
+
+        /// <summary>
+        /// The top-right corner of the anchor rectangle.
+        /// </summary>
         TopRight = Top | Right,
         TopRight = Top | Right,
+
+        /// <summary>
+        /// The bottom-left corner of the anchor rectangle.
+        /// </summary>
         BottomLeft = Bottom | Left,
         BottomLeft = Bottom | Left,
+
+        /// <summary>
+        /// The bottom-right corner of the anchor rectangle.
+        /// </summary>
         BottomRight = Bottom | Right,
         BottomRight = Bottom | Right,
 
 
-        
+        /// <summary>
+        /// A mask for the vertical component flags.
+        /// </summary>
         VerticalMask = Top | Bottom,
         VerticalMask = Top | Bottom,
+
+        /// <summary>
+        /// A mask for the horizontal component flags.
+        /// </summary>
         HorizontalMask = Left | Right,
         HorizontalMask = Left | Right,
+
+        /// <summary>
+        /// A mask for all flags.
+        /// </summary>
         AllMask = VerticalMask|HorizontalMask
         AllMask = VerticalMask|HorizontalMask
     }
     }
 
 
+    /// <summary>
+    /// Defines the direction in which a popup will open.
+    /// </summary>
+    [Flags]
+    public enum PopupGravity
+    {
+        /// <summary>
+        /// The popup will be centered over the anchor edge.
+        /// </summary>
+        None,
+
+        /// <summary>
+        /// The popup will be positioned above the anchor edge
+        /// </summary>
+        Top = 1,
+
+        /// <summary>
+        /// The popup will be positioned below the anchor edge
+        /// </summary>
+        Bottom = 2,
+
+        /// <summary>
+        /// The popup will be positioned to the left of the anchor edge
+        /// </summary>
+        Left = 4,
+
+        /// <summary>
+        /// The popup will be positioned to the right of the anchor edge
+        /// </summary>
+        Right = 8,
+
+        /// <summary>
+        /// The popup will be positioned to the top-left of the anchor edge
+        /// </summary>
+        TopLeft = Top | Left,
+
+        /// <summary>
+        /// The popup will be positioned to the top-right of the anchor edge
+        /// </summary>
+        TopRight = Top | Right,
+
+        /// <summary>
+        /// The popup will be positioned to the bottom-left of the anchor edge
+        /// </summary>
+        BottomLeft = Bottom | Left,
+
+        /// <summary>
+        /// The popup will be positioned to the bottom-right of the anchor edge
+        /// </summary>
+        BottomRight = Bottom | Right,
+    }
+
+    /// <summary>
+    /// Positions an <see cref="IPopupHost"/>.
+    /// </summary>
+    /// <remarks>
+    /// <see cref="IPopupPositioner"/> is an abstraction of the wayland xdg_positioner spec.
+    /// 
+    /// The popup positioner implementation is determined by the platform implementation. A default
+    /// managed implementation is provided in <see cref="ManagedPopupPositioner"/> for platforms
+    /// on which popups can be arbitrarily positioned.
+    /// </remarks>
     public interface IPopupPositioner
     public interface IPopupPositioner
     {
     {
+        /// <summary>
+        /// Updates the position of the associated <see cref="IPopupHost"/> according to the
+        /// specified parameters.
+        /// </summary>
+        /// <param name="parameters">The positioning parameters.</param>
         void Update(PopupPositionerParameters parameters);
         void Update(PopupPositionerParameters parameters);
     }
     }
 
 
@@ -296,18 +444,19 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
         public static void ConfigurePosition(ref this PopupPositionerParameters positionerParameters,
         public static void ConfigurePosition(ref this PopupPositionerParameters positionerParameters,
             TopLevel topLevel,
             TopLevel topLevel,
             IVisual target, PlacementMode placement, Point offset,
             IVisual target, PlacementMode placement, Point offset,
-            PopupPositioningEdge anchor, PopupPositioningEdge gravity)
+            PopupAnchor anchor, PopupGravity gravity,
+            PopupPositionerConstraintAdjustment constraintAdjustment, Rect? rect)
         {
         {
             // We need a better way for tracking the last pointer position
             // We need a better way for tracking the last pointer position
             var pointer = topLevel.PointToClient(topLevel.PlatformImpl.MouseDevice.Position);
             var pointer = topLevel.PointToClient(topLevel.PlatformImpl.MouseDevice.Position);
             
             
             positionerParameters.Offset = offset;
             positionerParameters.Offset = offset;
-            positionerParameters.ConstraintAdjustment = PopupPositionerConstraintAdjustment.All;
+            positionerParameters.ConstraintAdjustment = constraintAdjustment;
             if (placement == PlacementMode.Pointer)
             if (placement == PlacementMode.Pointer)
             {
             {
                 positionerParameters.AnchorRectangle = new Rect(pointer, new Size(1, 1));
                 positionerParameters.AnchorRectangle = new Rect(pointer, new Size(1, 1));
-                positionerParameters.Anchor = PopupPositioningEdge.TopLeft;
-                positionerParameters.Gravity = PopupPositioningEdge.BottomRight;
+                positionerParameters.Anchor = PopupAnchor.TopLeft;
+                positionerParameters.Gravity = PopupGravity.BottomRight;
             }
             }
             else
             else
             {
             {
@@ -317,32 +466,33 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
                 if (matrix == null)
                 if (matrix == null)
                 {
                 {
                     if (target.GetVisualRoot() == null)
                     if (target.GetVisualRoot() == null)
-                        throw new InvalidCastException("Target control is not attached to the visual tree");
-                    throw new InvalidCastException("Target control is not in the same tree as the popup parent");
+                        throw new InvalidOperationException("Target control is not attached to the visual tree");
+                    throw new InvalidOperationException("Target control is not in the same tree as the popup parent");
                 }
                 }
 
 
-                positionerParameters.AnchorRectangle = new Rect(default, target.Bounds.Size)
-                    .TransformToAABB(matrix.Value);
+                var bounds = new Rect(default, target.Bounds.Size);
+                var anchorRect = rect ?? bounds;
+                positionerParameters.AnchorRectangle = anchorRect.Intersect(bounds).TransformToAABB(matrix.Value);
 
 
                 if (placement == PlacementMode.Right)
                 if (placement == PlacementMode.Right)
                 {
                 {
-                    positionerParameters.Anchor = PopupPositioningEdge.TopRight;
-                    positionerParameters.Gravity = PopupPositioningEdge.BottomRight;
+                    positionerParameters.Anchor = PopupAnchor.TopRight;
+                    positionerParameters.Gravity = PopupGravity.BottomRight;
                 }
                 }
                 else if (placement == PlacementMode.Bottom)
                 else if (placement == PlacementMode.Bottom)
                 {
                 {
-                    positionerParameters.Anchor = PopupPositioningEdge.BottomLeft;
-                    positionerParameters.Gravity = PopupPositioningEdge.BottomRight;
+                    positionerParameters.Anchor = PopupAnchor.BottomLeft;
+                    positionerParameters.Gravity = PopupGravity.BottomRight;
                 }
                 }
                 else if (placement == PlacementMode.Left)
                 else if (placement == PlacementMode.Left)
                 {
                 {
-                    positionerParameters.Anchor = PopupPositioningEdge.TopLeft;
-                    positionerParameters.Gravity = PopupPositioningEdge.BottomLeft;
+                    positionerParameters.Anchor = PopupAnchor.TopLeft;
+                    positionerParameters.Gravity = PopupGravity.BottomLeft;
                 }
                 }
                 else if (placement == PlacementMode.Top)
                 else if (placement == PlacementMode.Top)
                 {
                 {
-                    positionerParameters.Anchor = PopupPositioningEdge.TopLeft;
-                    positionerParameters.Gravity = PopupPositioningEdge.TopRight;
+                    positionerParameters.Anchor = PopupAnchor.TopLeft;
+                    positionerParameters.Gravity = PopupGravity.TopRight;
                 }
                 }
                 else if (placement == PlacementMode.AnchorAndGravity)
                 else if (placement == PlacementMode.AnchorAndGravity)
                 {
                 {

+ 86 - 31
src/Avalonia.Controls/Primitives/PopupPositioning/ManagedPopupPositioner.cs

@@ -1,6 +1,7 @@
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
+using System.Transactions;
 
 
 namespace Avalonia.Controls.Primitives.PopupPositioning
 namespace Avalonia.Controls.Primitives.PopupPositioning
 {
 {
@@ -8,9 +9,8 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
     {
     {
         IReadOnlyList<ManagedPopupPositionerScreenInfo> Screens { get; }
         IReadOnlyList<ManagedPopupPositionerScreenInfo> Screens { get; }
         Rect ParentClientAreaScreenGeometry { get; }
         Rect ParentClientAreaScreenGeometry { get; }
+        double Scaling { get; }
         void MoveAndResize(Point devicePoint, Size virtualSize);
         void MoveAndResize(Point devicePoint, Size virtualSize);
-        Point TranslatePoint(Point pt);
-        Size TranslateSize(Size size);
     }
     }
 
 
     public class ManagedPopupPositionerScreenInfo
     public class ManagedPopupPositionerScreenInfo
@@ -25,6 +25,10 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
         }
         }
     }
     }
 
 
+    /// <summary>
+    /// An <see cref="IPopupPositioner"/> implementation for platforms on which a popup can be
+    /// aritrarily positioned.
+    /// </summary>
     public class ManagedPopupPositioner : IPopupPositioner
     public class ManagedPopupPositioner : IPopupPositioner
     {
     {
         private readonly IManagedPopupPositionerPopup _popup;
         private readonly IManagedPopupPositionerPopup _popup;
@@ -35,38 +39,38 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
         }
         }
 
 
 
 
-        private static Point GetAnchorPoint(Rect anchorRect, PopupPositioningEdge edge)
+        private static Point GetAnchorPoint(Rect anchorRect, PopupAnchor edge)
         {
         {
             double x, y;
             double x, y;
-            if ((edge & PopupPositioningEdge.Left) != 0)
+            if ((edge & PopupAnchor.Left) != 0)
                 x = anchorRect.X;
                 x = anchorRect.X;
-            else if ((edge & PopupPositioningEdge.Right) != 0)
+            else if ((edge & PopupAnchor.Right) != 0)
                 x = anchorRect.Right;
                 x = anchorRect.Right;
             else
             else
                 x = anchorRect.X + anchorRect.Width / 2;
                 x = anchorRect.X + anchorRect.Width / 2;
             
             
-            if ((edge & PopupPositioningEdge.Top) != 0)
+            if ((edge & PopupAnchor.Top) != 0)
                 y = anchorRect.Y;
                 y = anchorRect.Y;
-            else if ((edge & PopupPositioningEdge.Bottom) != 0)
+            else if ((edge & PopupAnchor.Bottom) != 0)
                 y = anchorRect.Bottom;
                 y = anchorRect.Bottom;
             else
             else
                 y = anchorRect.Y + anchorRect.Height / 2;
                 y = anchorRect.Y + anchorRect.Height / 2;
             return new Point(x, y);
             return new Point(x, y);
         }
         }
 
 
-        private static Point Gravitate(Point anchorPoint, Size size, PopupPositioningEdge gravity)
+        private static Point Gravitate(Point anchorPoint, Size size, PopupGravity gravity)
         {
         {
             double x, y;
             double x, y;
-            if ((gravity & PopupPositioningEdge.Left) != 0)
+            if ((gravity & PopupGravity.Left) != 0)
                 x = -size.Width;
                 x = -size.Width;
-            else if ((gravity & PopupPositioningEdge.Right) != 0)
+            else if ((gravity & PopupGravity.Right) != 0)
                 x = 0;
                 x = 0;
             else
             else
                 x = -size.Width / 2;
                 x = -size.Width / 2;
             
             
-            if ((gravity & PopupPositioningEdge.Top) != 0)
+            if ((gravity & PopupGravity.Top) != 0)
                 y = -size.Height;
                 y = -size.Height;
-            else if ((gravity & PopupPositioningEdge.Bottom) != 0)
+            else if ((gravity & PopupGravity.Bottom) != 0)
                 y = 0;
                 y = 0;
             else
             else
                 y = -size.Height / 2;
                 y = -size.Height / 2;
@@ -75,17 +79,24 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
 
 
         public void Update(PopupPositionerParameters parameters)
         public void Update(PopupPositionerParameters parameters)
         {
         {
-
-            Update(_popup.TranslateSize(parameters.Size), parameters.Size,
-                new Rect(_popup.TranslatePoint(parameters.AnchorRectangle.TopLeft),
-                    _popup.TranslateSize(parameters.AnchorRectangle.Size)),
-                parameters.Anchor, parameters.Gravity, parameters.ConstraintAdjustment,
-                _popup.TranslatePoint(parameters.Offset));
+            var rect = Calculate(
+                parameters.Size * _popup.Scaling,
+                new Rect(
+                    parameters.AnchorRectangle.TopLeft * _popup.Scaling,
+                    parameters.AnchorRectangle.Size * _popup.Scaling),
+                parameters.Anchor,
+                parameters.Gravity,
+                parameters.ConstraintAdjustment,
+                parameters.Offset * _popup.Scaling);
+           
+            _popup.MoveAndResize(
+                rect.Position,
+                rect.Size / _popup.Scaling);
         }
         }
 
 
         
         
-        private void Update(Size translatedSize, Size originalSize,
-            Rect anchorRect, PopupPositioningEdge anchor, PopupPositioningEdge gravity,
+        private Rect Calculate(Size translatedSize, 
+            Rect anchorRect, PopupAnchor anchor, PopupGravity gravity,
             PopupPositionerConstraintAdjustment constraintAdjustment, Point offset)
             PopupPositionerConstraintAdjustment constraintAdjustment, Point offset)
         {
         {
             var parentGeometry = _popup.ParentClientAreaScreenGeometry;
             var parentGeometry = _popup.ParentClientAreaScreenGeometry;
@@ -112,28 +123,30 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
 
 
             var bounds = GetBounds();
             var bounds = GetBounds();
 
 
-            bool FitsInBounds(Rect rc, PopupPositioningEdge edge = PopupPositioningEdge.AllMask)
+            bool FitsInBounds(Rect rc, PopupAnchor edge = PopupAnchor.AllMask)
             {
             {
-                if ((edge & PopupPositioningEdge.Left) != 0
+                if ((edge & PopupAnchor.Left) != 0
                     && rc.X < bounds.X)
                     && rc.X < bounds.X)
                     return false;
                     return false;
 
 
-                if ((edge & PopupPositioningEdge.Top) != 0
+                if ((edge & PopupAnchor.Top) != 0
                     && rc.Y < bounds.Y)
                     && rc.Y < bounds.Y)
                     return false;
                     return false;
 
 
-                if ((edge & PopupPositioningEdge.Right) != 0
+                if ((edge & PopupAnchor.Right) != 0
                     && rc.Right > bounds.Right)
                     && rc.Right > bounds.Right)
                     return false;
                     return false;
 
 
-                if ((edge & PopupPositioningEdge.Bottom) != 0
+                if ((edge & PopupAnchor.Bottom) != 0
                     && rc.Bottom > bounds.Bottom)
                     && rc.Bottom > bounds.Bottom)
                     return false;
                     return false;
 
 
                 return true;
                 return true;
             }
             }
 
 
-            Rect GetUnconstrained(PopupPositioningEdge a, PopupPositioningEdge g) =>
+            static bool IsValid(in Rect rc) => rc.Width > 0 && rc.Height > 0;
+
+            Rect GetUnconstrained(PopupAnchor a, PopupGravity g) =>
                 new Rect(Gravitate(GetAnchorPoint(anchorRect, a), translatedSize, g) + offset, translatedSize);
                 new Rect(Gravitate(GetAnchorPoint(anchorRect, a), translatedSize, g) + offset, translatedSize);
 
 
 
 
@@ -141,11 +154,11 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
 
 
             // If flipping geometry and anchor is allowed and helps, use the flipped one,
             // If flipping geometry and anchor is allowed and helps, use the flipped one,
             // otherwise leave it as is
             // otherwise leave it as is
-            if (!FitsInBounds(geo, PopupPositioningEdge.HorizontalMask)
+            if (!FitsInBounds(geo, PopupAnchor.HorizontalMask)
                 && (constraintAdjustment & PopupPositionerConstraintAdjustment.FlipX) != 0)
                 && (constraintAdjustment & PopupPositionerConstraintAdjustment.FlipX) != 0)
             {
             {
                 var flipped = GetUnconstrained(anchor.FlipX(), gravity.FlipX());
                 var flipped = GetUnconstrained(anchor.FlipX(), gravity.FlipX());
-                if (FitsInBounds(flipped, PopupPositioningEdge.HorizontalMask))
+                if (FitsInBounds(flipped, PopupAnchor.HorizontalMask))
                     geo = geo.WithX(flipped.X);
                     geo = geo.WithX(flipped.X);
             }
             }
 
 
@@ -157,13 +170,34 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
                     geo = geo.WithX(bounds.Right - geo.Width);
                     geo = geo.WithX(bounds.Right - geo.Width);
             }
             }
             
             
+            // Resize the rect horizontally if allowed.
+            if ((constraintAdjustment & PopupPositionerConstraintAdjustment.ResizeX) != 0)
+            {
+                var unconstrainedRect = geo;
+
+                if (!FitsInBounds(unconstrainedRect, PopupAnchor.Left))
+                {
+                    unconstrainedRect = unconstrainedRect.WithX(bounds.X);
+                }
+
+                if (!FitsInBounds(unconstrainedRect, PopupAnchor.Right))
+                {
+                    unconstrainedRect = unconstrainedRect.WithWidth(bounds.Width - unconstrainedRect.X);
+                }
+
+                if (IsValid(unconstrainedRect))
+                {
+                    geo = unconstrainedRect;
+                }
+            }
+
             // If flipping geometry and anchor is allowed and helps, use the flipped one,
             // If flipping geometry and anchor is allowed and helps, use the flipped one,
             // otherwise leave it as is
             // otherwise leave it as is
-            if (!FitsInBounds(geo, PopupPositioningEdge.VerticalMask)
+            if (!FitsInBounds(geo, PopupAnchor.VerticalMask)
                 && (constraintAdjustment & PopupPositionerConstraintAdjustment.FlipY) != 0)
                 && (constraintAdjustment & PopupPositionerConstraintAdjustment.FlipY) != 0)
             {
             {
                 var flipped = GetUnconstrained(anchor.FlipY(), gravity.FlipY());
                 var flipped = GetUnconstrained(anchor.FlipY(), gravity.FlipY());
-                if (FitsInBounds(flipped, PopupPositioningEdge.VerticalMask))
+                if (FitsInBounds(flipped, PopupAnchor.VerticalMask))
                     geo = geo.WithY(flipped.Y);
                     geo = geo.WithY(flipped.Y);
             }
             }
 
 
@@ -175,7 +209,28 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
                     geo = geo.WithY(bounds.Bottom - geo.Height);
                     geo = geo.WithY(bounds.Bottom - geo.Height);
             }
             }
 
 
-            _popup.MoveAndResize(geo.TopLeft, originalSize);
+            // Resize the rect vertically if allowed.
+            if ((constraintAdjustment & PopupPositionerConstraintAdjustment.ResizeY) != 0)
+            {
+                var unconstrainedRect = geo;
+
+                if (!FitsInBounds(unconstrainedRect, PopupAnchor.Top))
+                {
+                    unconstrainedRect = unconstrainedRect.WithY(bounds.Y);
+                }
+
+                if (!FitsInBounds(unconstrainedRect, PopupAnchor.Bottom))
+                {
+                    unconstrainedRect = unconstrainedRect.WithHeight(bounds.Height - unconstrainedRect.Y);
+                }
+
+                if (IsValid(unconstrainedRect))
+                {
+                    geo = unconstrainedRect;
+                }
+            }
+
+            return geo;
         }
         }
     }
     }
 }
 }

+ 2 - 4
src/Avalonia.Controls/Primitives/PopupPositioning/ManagedPopupPositionerPopupImplHelper.cs

@@ -32,7 +32,7 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
             {
             {
                 // Popup positioner operates with abstract coordinates, but in our case they are pixel ones
                 // Popup positioner operates with abstract coordinates, but in our case they are pixel ones
                 var point = _parent.PointToScreen(default);
                 var point = _parent.PointToScreen(default);
-                var size = TranslateSize(_parent.ClientSize);
+                var size = _parent.ClientSize * Scaling;
                 return new Rect(point.X, point.Y, size.Width, size.Height);
                 return new Rect(point.X, point.Y, size.Width, size.Height);
 
 
             }
             }
@@ -43,8 +43,6 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
             _moveResize(new PixelPoint((int)devicePoint.X, (int)devicePoint.Y), virtualSize, _parent.Scaling);
             _moveResize(new PixelPoint((int)devicePoint.X, (int)devicePoint.Y), virtualSize, _parent.Scaling);
         }
         }
 
 
-        public virtual Point TranslatePoint(Point pt) => pt * _parent.Scaling;
-
-        public virtual Size TranslateSize(Size size) => size * _parent.Scaling;
+        public virtual double Scaling => _parent.Scaling;
     }
     }
 }
 }

+ 5 - 3
src/Avalonia.Controls/Primitives/PopupRoot.cs

@@ -82,11 +82,13 @@ namespace Avalonia.Controls.Primitives
         }
         }
 
 
         public void ConfigurePosition(IVisual target, PlacementMode placement, Point offset,
         public void ConfigurePosition(IVisual target, PlacementMode placement, Point offset,
-            PopupPositioningEdge anchor = PopupPositioningEdge.None,
-            PopupPositioningEdge gravity = PopupPositioningEdge.None)
+            PopupAnchor anchor = PopupAnchor.None,
+            PopupGravity gravity = PopupGravity.None,
+            PopupPositionerConstraintAdjustment constraintAdjustment = PopupPositionerConstraintAdjustment.All,
+            Rect? rect = null)
         {
         {
             _positionerParameters.ConfigurePosition(_parent, target,
             _positionerParameters.ConfigurePosition(_parent, target,
-                placement, offset, anchor, gravity);
+                placement, offset, anchor, gravity, constraintAdjustment, rect);
 
 
             if (_positionerParameters.Size != default)
             if (_positionerParameters.Size != default)
                 UpdatePosition();
                 UpdatePosition();

+ 1 - 1
src/Avalonia.Controls/Primitives/Track.cs

@@ -259,7 +259,7 @@ namespace Avalonia.Controls.Primitives
                 CoerceLength(ref increaseButtonLength, arrangeSize.Width);
                 CoerceLength(ref increaseButtonLength, arrangeSize.Width);
                 CoerceLength(ref thumbLength, arrangeSize.Width);
                 CoerceLength(ref thumbLength, arrangeSize.Width);
 
 
-                offset = offset.WithY(isDirectionReversed ? increaseButtonLength + thumbLength : 0.0);
+                offset = offset.WithX(isDirectionReversed ? increaseButtonLength + thumbLength : 0.0);
                 pieceSize = pieceSize.WithWidth(decreaseButtonLength);
                 pieceSize = pieceSize.WithWidth(decreaseButtonLength);
 
 
                 if (DecreaseButton != null)
                 if (DecreaseButton != null)

+ 1 - 1
src/Avalonia.Controls/Slider.cs

@@ -201,7 +201,7 @@ namespace Avalonia.Controls
             var invert = orient ? 0 : 1;
             var invert = orient ? 0 : 1;
             var calcVal = Math.Abs(invert - logicalPos);
             var calcVal = Math.Abs(invert - logicalPos);
             var range = Maximum - Minimum;
             var range = Maximum - Minimum;
-            var finalValue = calcVal * range;
+            var finalValue = calcVal * range + Minimum;
 
 
             Value = IsSnapToTickEnabled ? SnapToTick(finalValue) : finalValue;
             Value = IsSnapToTickEnabled ? SnapToTick(finalValue) : finalValue;
         }
         }

+ 105 - 0
src/Avalonia.Controls/ToggleSwitch.cs

@@ -0,0 +1,105 @@
+using Avalonia.Controls.Primitives;
+using Avalonia.Controls.Templates;
+using Avalonia.LogicalTree;
+
+namespace Avalonia.Controls
+{
+    /// <summary>
+    /// A Toggle Switch control.
+    /// </summary>
+    public class ToggleSwitch : ToggleButton
+    {
+        static ToggleSwitch()
+        {
+            OffContentProperty.Changed.AddClassHandler<ToggleSwitch>((x, e) => x.OffContentChanged(e));
+            OnContentProperty.Changed.AddClassHandler<ToggleSwitch>((x, e) => x.OnContentChanged(e));
+        }
+
+        /// <summary>
+        /// Defines the <see cref="OffContent"/> property.
+        /// </summary>
+        public static readonly StyledProperty<object> OffContentProperty =
+         AvaloniaProperty.Register<ToggleSwitch, object>(nameof(OffContent), defaultValue: "Off");
+
+        /// <summary>
+        /// Defines the <see cref="OffContentTemplate"/> property.
+        /// </summary>
+        public static readonly StyledProperty<IDataTemplate> OffContentTemplateProperty =
+            AvaloniaProperty.Register<ToggleSwitch, IDataTemplate>(nameof(OffContentTemplate));
+
+        /// <summary>
+        /// Defines the <see cref="OnContent"/> property.
+        /// </summary>
+        public static readonly StyledProperty<object> OnContentProperty =
+            AvaloniaProperty.Register<ToggleSwitch, object>(nameof(OnContent), defaultValue: "On");
+
+        /// <summary>
+        /// Defines the <see cref="OnContentTemplate"/> property.
+        /// </summary>
+        public static readonly StyledProperty<IDataTemplate> OnContentTemplateProperty =
+            AvaloniaProperty.Register<ToggleSwitch, IDataTemplate>(nameof(OnContentTemplate));
+
+        /// <summary>
+        /// Gets or Sets the Content that is displayed when in the On State.
+        /// </summary>
+        public object OnContent
+        {
+            get { return GetValue(OnContentProperty); }
+            set { SetValue(OnContentProperty, value); }
+        }
+
+        /// <summary>
+        /// Gets or Sets the Content that is displayed when in the Off State.
+        /// </summary>
+        public object OffContent
+        {
+            get { return GetValue(OffContentProperty); }
+            set { SetValue(OffContentProperty, value); }
+        }
+
+        /// <summary>
+        /// Gets or Sets the <see cref="IDataTemplate"/> used to display the <see cref="OffContent"/>.
+        /// </summary>
+        public IDataTemplate OffContentTemplate
+        {
+            get { return GetValue(OffContentTemplateProperty); }
+            set { SetValue(OffContentTemplateProperty, value); }
+        }
+
+        /// <summary>
+        /// Gets or Sets the <see cref="IDataTemplate"/> used to display the <see cref="OnContent"/>.
+        /// </summary>
+        public IDataTemplate OnContentTemplate
+        {
+            get { return GetValue(OnContentTemplateProperty); }
+            set { SetValue(OnContentTemplateProperty, value); }
+        }
+
+        private void OffContentChanged(AvaloniaPropertyChangedEventArgs e)
+        {
+            if (e.OldValue is ILogical oldChild)
+            {
+                LogicalChildren.Remove(oldChild);
+            }
+
+            if (e.NewValue is ILogical newChild)
+            {
+                LogicalChildren.Add(newChild);
+            }
+        }
+
+        private void OnContentChanged(AvaloniaPropertyChangedEventArgs e)
+        {
+            if (e.OldValue is ILogical oldChild)
+            {
+                LogicalChildren.Remove(oldChild);
+            }
+
+            if (e.NewValue is ILogical newChild)
+            {
+                LogicalChildren.Add(newChild);
+            }
+        }
+    }
+}
+

+ 1 - 2
src/Avalonia.Native/OsxManagedPopupPositionerPopupImplHelper.cs

@@ -9,8 +9,7 @@ namespace Avalonia.Native
         {
         {
 
 
         }
         }
-        public override Point TranslatePoint(Point pt) => pt;
 
 
-        public override Size TranslateSize(Size size) => size;
+        public override double Scaling => 1;
     }
     }
 }
 }

+ 1 - 0
src/Avalonia.Themes.Default/DefaultTheme.xaml

@@ -52,4 +52,5 @@
   <StyleInclude Source="resm:Avalonia.Themes.Default.WindowNotificationManager.xaml?assembly=Avalonia.Themes.Default"/>
   <StyleInclude Source="resm:Avalonia.Themes.Default.WindowNotificationManager.xaml?assembly=Avalonia.Themes.Default"/>
   <StyleInclude Source="resm:Avalonia.Themes.Default.NotificationCard.xaml?assembly=Avalonia.Themes.Default"/>
   <StyleInclude Source="resm:Avalonia.Themes.Default.NotificationCard.xaml?assembly=Avalonia.Themes.Default"/>
   <StyleInclude Source="resm:Avalonia.Themes.Default.NativeMenuBar.xaml?assembly=Avalonia.Themes.Default"/>
   <StyleInclude Source="resm:Avalonia.Themes.Default.NativeMenuBar.xaml?assembly=Avalonia.Themes.Default"/>
+  <StyleInclude Source="resm:Avalonia.Themes.Default.ToggleSwitch.xaml?assembly=Avalonia.Themes.Default"/>
 </Styles>
 </Styles>

+ 294 - 0
src/Avalonia.Themes.Default/ToggleSwitch.xaml

@@ -0,0 +1,294 @@
+<Styles xmlns="https://github.com/avaloniaui"
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+        xmlns:sys="clr-namespace:System;assembly=netstandard">
+  <Styles.Resources>
+    <Thickness x:Key="ToggleSwitchTopHeaderMargin">0,0,0,6</Thickness>
+    <x:Double x:Key="ToggleSwitchPreContentMargin">6</x:Double>
+    <x:Double x:Key="ToggleSwitchPostContentMargin">6</x:Double>
+    <x:Double x:Key="ToggleSwitchThemeMinWidth">154</x:Double>
+    <x:Double x:Key="KnobOnPosition">20</x:Double>
+    <x:Double x:Key="KnobOffPosition">0</x:Double>
+  </Styles.Resources>
+  <Design.PreviewWith>
+    <StackPanel Margin="20" Width="250" Spacing="24" >
+      <StackPanel Spacing="12" >
+        <TextBlock
+          Text="Automatic updates"
+          Classes="h1"/>
+        <TextBlock
+          Text="Updates will be automaticly Downloaded and installed shile the computer is shutting down or restarting"
+          TextWrapping="Wrap"/>
+        <ToggleSwitch HorizontalContentAlignment="Left"
+          Content="Enable automatic Updates?"
+          OffContent="Uit"
+          OnContent="Aan"
+          VerticalAlignment="Bottom"/>
+      </StackPanel>
+
+      <StackPanel Spacing="12">
+        <TextBlock
+          Text="Previewer"
+          Classes="h1"/>
+        <TextBlock
+          Text="The previewer Shows a preview off your code, this could slow down your system"
+          TextWrapping="Wrap"/>
+        <ToggleSwitch
+          Content="Previewer"
+          IsChecked="True" />
+      </StackPanel>
+    </StackPanel>
+  </Design.PreviewWith>
+
+  <Style Selector="ToggleSwitch">
+    <Setter Property="Foreground" Value="{DynamicResource ToggleSwitchContentForeground}" />
+    <Setter Property="HorizontalAlignment" Value="Left" />
+    <Setter Property="VerticalAlignment" Value="Center" />
+    <Setter Property="HorizontalContentAlignment" Value="Left" />
+    <Setter Property="FontFamily" Value="{DynamicResource ContentControlThemeFontFamily}" />
+    <Setter Property="FontSize" Value="{DynamicResource ControlContentThemeFontSize}" />
+    <Setter Property="Template">
+      <ControlTemplate>
+        <Grid Background="{TemplateBinding Background}"
+          RowDefinitions="Auto,*">
+
+          <ContentPresenter x:Name="PART_ContentPresenter"
+            Grid.Row="0"
+            Content="{TemplateBinding Content}"
+            ContentTemplate="{TemplateBinding ContentTemplate}"
+            Margin="{DynamicResource ToggleSwitchTopHeaderMargin}"
+            VerticalAlignment="Top"/>
+
+          <Grid Grid.Row="1"
+            MinWidth="{StaticResource ToggleSwitchThemeMinWidth}"
+            HorizontalAlignment="Left"
+            VerticalAlignment="Top">
+
+            <Grid.RowDefinitions>
+              <RowDefinition Height="{DynamicResource ToggleSwitchPreContentMargin}" />
+              <RowDefinition Height="Auto" />
+              <RowDefinition Height="{DynamicResource ToggleSwitchPostContentMargin}" />
+            </Grid.RowDefinitions>
+
+            <Grid.ColumnDefinitions>
+              <ColumnDefinition Width="Auto" />
+              <ColumnDefinition Width="12" MaxWidth="12" />
+              <ColumnDefinition Width="Auto" />
+            </Grid.ColumnDefinitions>
+
+            <Grid x:Name="SwitchAreaGrid"
+              Grid.RowSpan="3"
+              Grid.ColumnSpan="3"
+              TemplatedControl.IsTemplateFocusTarget="True"
+              Margin="0,5" />
+
+            <ContentPresenter x:Name="PART_OffContentPresenter"
+              Grid.RowSpan="3"
+              Grid.Column="2"
+              Content="{TemplateBinding OffContent}"
+              ContentTemplate="{TemplateBinding OffContentTemplate}"
+              HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
+              VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
+
+            <ContentPresenter x:Name="PART_OnContentPresenter"
+              Grid.RowSpan="3"
+              Grid.Column="2"
+              Content="{TemplateBinding OnContent}"
+              ContentTemplate="{TemplateBinding OnContentTemplate}"
+              HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
+              VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
+
+            <Border x:Name="OuterBorder"
+              Grid.Row="1"
+              Height="20"
+              Width="40"
+              CornerRadius="10"
+              BorderThickness="{DynamicResource ToggleSwitchOuterBorderStrokeThickness}" />
+
+            <Border x:Name="SwitchKnobBounds"
+              Grid.Row="1"
+              Height="20"
+              Width="40"
+              CornerRadius="10"
+              BorderThickness="{DynamicResource ToggleSwitchOnStrokeThickness}"/>
+
+            <Canvas x:Name="SwitchKnob" Grid.Row="1"
+               HorizontalAlignment="Left"
+               Width="20" Height="20">
+
+              <Grid x:Name="MovingKnobs"
+                Width="20" Height="20">
+
+                <Ellipse x:Name="SwitchKnobOn"
+                         Width="10" Height="10" />
+
+                <Ellipse x:Name="SwitchKnobOff"
+                         Width="10" Height="10" />
+              </Grid>
+            </Canvas>
+          </Grid>
+        </Grid>
+      </ControlTemplate>
+    </Setter>
+  </Style>
+
+  <!-- NormalState -->
+  <Style Selector="ToggleSwitch /template/ Grid#SwitchAreaGrid">
+    <Setter Property="Background" Value="{DynamicResource ToggleSwitchContainerBackground}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch /template/ Border#OuterBorder">
+    <Setter Property="Background" Value="{DynamicResource ToggleSwitchFillOff}"/>
+    <Setter Property="BorderBrush" Value="{DynamicResource ToggleSwitchStrokeOff}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch /template/ Border#SwitchKnobBounds">
+    <Setter Property="Background" Value="{DynamicResource ToggleSwitchFillOn}"/>
+    <Setter Property="BorderBrush" Value="{DynamicResource ToggleSwitchStrokeOn}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch /template/ Ellipse#SwitchKnobOn">
+    <Setter Property="Fill" Value="{DynamicResource ToggleSwitchKnobFillOn}"/>
+    <Setter Property="Stroke" Value="{DynamicResource ToggleSwitchKnobStrokeOn}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch /template/ Ellipse#SwitchKnobOff">
+    <Setter Property="Fill" Value="{DynamicResource ToggleSwitchKnobFillOff}"/>
+    <Setter Property="Stroke" Value="{DynamicResource ToggleSwitchKnobStrokeOff}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch /template/ Grid#MovingKnobs">
+    <Setter Property="Canvas.Left" Value="{DynamicResource KnobOffPosition}"/>
+    <Setter Property="Transitions">
+      <Transitions>
+        <DoubleTransition Property="Canvas.Left" Duration="0:0:0.2" Easing="CubicEaseOut"/>
+      </Transitions>
+    </Setter>
+  </Style>
+
+  <!-- PointerOverState -->
+  <Style Selector="ToggleSwitch:pointerover /template/ Border#OuterBorder">
+    <Setter Property="BorderBrush" Value="{DynamicResource ToggleSwitchStrokeOffPointerOver}"/>
+    <Setter Property="Background" Value="{DynamicResource ToggleSwitchFillOffPointerOver}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:pointerover /template/ Ellipse#SwitchKnobOff">
+    <Setter Property="Fill" Value="{DynamicResource ToggleSwitchKnobFillOffPointerOver}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:pointerover /template/ Ellipse#SwitchKnobOn">
+    <Setter Property="Fill" Value="{DynamicResource ToggleSwitchKnobFillOnPointerOver}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:pointerover /template/ Border#SwitchKnobBounds">
+    <Setter Property="Background" Value="{DynamicResource ToggleSwitchFillOnPointerOver}"/>
+    <Setter Property="BorderBrush" Value="{DynamicResource ToggleSwitchStrokeOnPointerOver}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:pointerover /template/ Grid#SwitchAreaGrid">
+    <Setter Property="Background" Value="{DynamicResource ToggleSwitchContainerBackgroundPointerOver}"/>
+  </Style>
+
+  <!-- PressedState -->
+  <Style Selector="ToggleSwitch:pressed /template/ Border#OuterBorder">
+    <Setter Property="BorderBrush" Value="{DynamicResource ToggleSwitchStrokeOffPressed}"/>
+    <Setter Property="Background" Value="{DynamicResource ToggleSwitchFillOffPressed}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:pressed /template/ Border#SwitchKnobBounds">
+    <Setter Property="Background" Value="{DynamicResource ToggleSwitchFillOnPressed}"/>
+    <Setter Property="BorderBrush" Value="{DynamicResource ToggleSwitchStrokeOnPressed}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:pressed /template/ Ellipse#SwitchKnobOff">
+    <Setter Property="Fill" Value="{DynamicResource ToggleSwitchKnobFillOffPressed}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:pressed /template/ Ellipse#SwitchKnobOn">
+    <Setter Property="Fill" Value="{DynamicResource ToggleSwitchKnobFillOnPressed}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:pressed /template/ Grid#SwitchAreaGrid">
+    <Setter Property="Background" Value="{DynamicResource ToggleSwitchContainerBackgroundPressed}"/>
+  </Style>
+
+  <!-- DisabledState -->
+  <Style Selector="ToggleSwitch:disabled">
+    <Setter Property="Foreground" Value="{DynamicResource ToggleSwitchHeaderForegroundDisabled}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:disabled /template/ Border#OuterBorder">
+    <Setter Property="BorderBrush" Value="{DynamicResource ToggleSwitchStrokeOffDisabled}"/>
+    <Setter Property="Background" Value="{DynamicResource ToggleSwitchFillOffPressed}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:disabled /template/ Ellipse#SwitchKnobOff">
+    <Setter Property="Fill" Value="{DynamicResource ToggleSwitchKnobFillOffDisabled}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:disabled /template/ Ellipse#SwitchKnobOn">
+    <Setter Property="Fill" Value="{DynamicResource ToggleSwitchKnobFillOnDisabled}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:disabled /template/ Border#SwitchKnobBounds">
+    <Setter Property="Background" Value="{DynamicResource ToggleSwitchFillOnDisabled}"/>
+    <Setter Property="BorderBrush" Value="{DynamicResource ToggleSwitchStrokeOnDisabled}"/>
+  </Style>
+
+  <!-- CheckedState -->
+  <Style Selector="ToggleSwitch:checked /template/ Grid#MovingKnobs">
+    <Setter Property="Canvas.Left" Value="{DynamicResource KnobOnPosition}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:checked /template/ Border#OuterBorder">
+    <Setter Property="Opacity" Value="0"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:checked  /template/ Ellipse#SwitchKnobOff">
+    <Setter Property="Opacity" Value="0"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:checked  /template/ Border#SwitchKnobBounds">
+    <Setter Property="Opacity" Value="1"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:checked /template/ Ellipse#SwitchKnobOn">
+    <Setter Property="Opacity" Value="1"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:checked /template/ ContentPresenter#PART_OffContentPresenter">
+    <Setter Property="Opacity" Value="0"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:checked /template/ ContentPresenter#PART_OnContentPresenter">
+    <Setter Property="Opacity" Value="1"/>
+  </Style>
+
+  <!--UncheckedState -->
+  <Style Selector="ToggleSwitch:unchecked /template/ Grid#MovingKnobs">
+    <Setter Property="Canvas.Left" Value="{DynamicResource KnobOffPosition}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:unchecked /template/ Border#OuterBorder">
+    <Setter Property="Opacity" Value="1"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:unchecked /template/ Ellipse#SwitchKnobOff">
+    <Setter Property="Opacity" Value="1"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:unchecked /template/ Ellipse#SwitchKnobOn">
+    <Setter Property="Opacity" Value="0"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:unchecked  /template/ Border#SwitchKnobBounds">
+    <Setter Property="Opacity" Value="0"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:unchecked /template/ ContentPresenter#PART_OffContentPresenter">
+    <Setter Property="Opacity" Value="1"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:unchecked /template/ ContentPresenter#PART_OnContentPresenter">
+    <Setter Property="Opacity" Value="0"/>
+  </Style>
+</Styles>

+ 3 - 0
src/Avalonia.Themes.Fluent/Accents/BaseDark.xaml

@@ -138,6 +138,9 @@
     <SolidColorBrush x:Key="SystemControlTransparentBrush" Color="Transparent" />
     <SolidColorBrush x:Key="SystemControlTransparentBrush" Color="Transparent" />
     <SolidColorBrush x:Key="SystemControlErrorTextForegroundBrush" Color="{StaticResource SystemErrorTextColor}" />
     <SolidColorBrush x:Key="SystemControlErrorTextForegroundBrush" Color="{StaticResource SystemErrorTextColor}" />
     <SolidColorBrush x:Key="SystemControlTransientBorderBrush" Color="#000000" Opacity="0.36" />
     <SolidColorBrush x:Key="SystemControlTransientBorderBrush" Color="#000000" Opacity="0.36" />
+    <SolidColorBrush x:Key="SystemControlHighlightListLowRevealBackgroundBrush" Color="{StaticResource SystemListMediumColor}" />
+    <SolidColorBrush x:Key="SystemControlHighlightListMediumRevealBackgroundBrush" Color="{StaticResource SystemListMediumColor}" />
+    <SolidColorBrush x:Key="SystemControlHighlightAccentRevealBackgroundBrush" Color="{StaticResource SystemAccentColor}" />
     <!-- TODO implement AcrylicBrush -->
     <!-- TODO implement AcrylicBrush -->
     <!--<AcrylicBrush x:Key="SystemControlTransientBackgroundBrush" BackgroundSource="HostBackdrop" TintColor="{StaticResource SystemChromeAltHighColor}" TintOpacity="0.8" FallbackColor="{StaticResource SystemChromeMediumLowColor}" />-->
     <!--<AcrylicBrush x:Key="SystemControlTransientBackgroundBrush" BackgroundSource="HostBackdrop" TintColor="{StaticResource SystemChromeAltHighColor}" TintOpacity="0.8" FallbackColor="{StaticResource SystemChromeMediumLowColor}" />-->
     <SolidColorBrush x:Key="SystemControlTransientBackgroundBrush" Color="{StaticResource SystemChromeMediumLowColor}" />
     <SolidColorBrush x:Key="SystemControlTransientBackgroundBrush" Color="{StaticResource SystemChromeMediumLowColor}" />

+ 3 - 0
src/Avalonia.Themes.Fluent/Accents/BaseLight.xaml

@@ -138,6 +138,9 @@
     <SolidColorBrush x:Key="SystemControlTransparentBrush" Color="Transparent" />
     <SolidColorBrush x:Key="SystemControlTransparentBrush" Color="Transparent" />
     <SolidColorBrush x:Key="SystemControlErrorTextForegroundBrush" Color="{StaticResource SystemErrorTextColor}" />
     <SolidColorBrush x:Key="SystemControlErrorTextForegroundBrush" Color="{StaticResource SystemErrorTextColor}" />
     <SolidColorBrush x:Key="SystemControlTransientBorderBrush" Color="#000000" Opacity="0.14" />
     <SolidColorBrush x:Key="SystemControlTransientBorderBrush" Color="#000000" Opacity="0.14" />
+    <SolidColorBrush x:Key="SystemControlHighlightListLowRevealBackgroundBrush" Color="{StaticResource SystemListMediumColor}" />
+    <SolidColorBrush x:Key="SystemControlHighlightListMediumRevealBackgroundBrush" Color="{StaticResource SystemListMediumColor}" />
+    <SolidColorBrush x:Key="SystemControlHighlightAccentRevealBackgroundBrush" Color="{StaticResource SystemAccentColor}" />
     <!-- TODO implement AcrylicBrush -->
     <!-- TODO implement AcrylicBrush -->
     <!--<AcrylicBrush x:Key="SystemControlTransientBackgroundBrush" BackgroundSource="HostBackdrop" TintColor="{StaticResource SystemChromeAltHighColor}" TintOpacity="0.8" FallbackColor="{StaticResource SystemChromeMediumLowColor}" />-->
     <!--<AcrylicBrush x:Key="SystemControlTransientBackgroundBrush" BackgroundSource="HostBackdrop" TintColor="{StaticResource SystemChromeAltHighColor}" TintOpacity="0.8" FallbackColor="{StaticResource SystemChromeMediumLowColor}" />-->
     <SolidColorBrush x:Key="SystemControlTransientBackgroundBrush" Color="{StaticResource SystemChromeMediumLowColor}" />
     <SolidColorBrush x:Key="SystemControlTransientBackgroundBrush" Color="{StaticResource SystemChromeMediumLowColor}" />

+ 151 - 6
src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesDark.xaml

@@ -1,5 +1,5 @@
-<Style xmlns="https://github.com/avaloniaui" 
-  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
+<Style xmlns="https://github.com/avaloniaui"
+  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:sys="clr-namespace:System;assembly=netstandard">
   xmlns:sys="clr-namespace:System;assembly=netstandard">
   <Style.Resources>
   <Style.Resources>
     <!-- Resources for Button.xaml -->
     <!-- Resources for Button.xaml -->
@@ -62,7 +62,7 @@
     <SolidColorBrush x:Key="RepeatButtonPointerOverForegroundThemeBrush" Color="#FFFFFFFF" />
     <SolidColorBrush x:Key="RepeatButtonPointerOverForegroundThemeBrush" Color="#FFFFFFFF" />
     <SolidColorBrush x:Key="RepeatButtonPressedBackgroundThemeBrush" Color="#FFFFFFFF" />
     <SolidColorBrush x:Key="RepeatButtonPressedBackgroundThemeBrush" Color="#FFFFFFFF" />
     <SolidColorBrush x:Key="RepeatButtonPressedForegroundThemeBrush" Color="#FF000000" />
     <SolidColorBrush x:Key="RepeatButtonPressedForegroundThemeBrush" Color="#FF000000" />
-    
+
     <!-- Resources for ToggleButton.xaml -->
     <!-- Resources for ToggleButton.xaml -->
     <Thickness x:Key="ToggleButtonBorderThemeThickness">1</Thickness>
     <Thickness x:Key="ToggleButtonBorderThemeThickness">1</Thickness>
     <StaticResource x:Key="ToggleButtonBackground" ResourceKey="SystemControlBackgroundBaseLowBrush" />
     <StaticResource x:Key="ToggleButtonBackground" ResourceKey="SystemControlBackgroundBaseLowBrush" />
@@ -182,8 +182,8 @@
     <StaticResource x:Key="ComboBoxDropDownGlyphForeground" ResourceKey="SystemControlForegroundBaseMediumHighBrush" />
     <StaticResource x:Key="ComboBoxDropDownGlyphForeground" ResourceKey="SystemControlForegroundBaseMediumHighBrush" />
     <StaticResource x:Key="ComboBoxDropDownGlyphForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
     <StaticResource x:Key="ComboBoxDropDownGlyphForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
     <StaticResource x:Key="ComboBoxDropDownGlyphForegroundFocused" ResourceKey="SystemControlHighlightAltBaseMediumHighBrush" />
     <StaticResource x:Key="ComboBoxDropDownGlyphForegroundFocused" ResourceKey="SystemControlHighlightAltBaseMediumHighBrush" />
-    <StaticResource x:Key="ComboBoxDropDownGlyphForegroundFocusedPressed" ResourceKey="SystemControlHighlightAltBaseMediumHighBrush" />    
-    <StaticResource x:Key="ComboBoxDropDownForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />    
+    <StaticResource x:Key="ComboBoxDropDownGlyphForegroundFocusedPressed" ResourceKey="SystemControlHighlightAltBaseMediumHighBrush" />
+    <StaticResource x:Key="ComboBoxDropDownForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
     <StaticResource x:Key="ComboBoxDropDownBackground" ResourceKey="SystemControlTransientBackgroundBrush" />
     <StaticResource x:Key="ComboBoxDropDownBackground" ResourceKey="SystemControlTransientBackgroundBrush" />
     <StaticResource x:Key="ComboBoxDropDownBorderBrush" ResourceKey="SystemControlTransientBorderBrush" />
     <StaticResource x:Key="ComboBoxDropDownBorderBrush" ResourceKey="SystemControlTransientBorderBrush" />
 
 
@@ -250,6 +250,92 @@
     <SolidColorBrush x:Key="ListBoxItemSelectedForegroundThemeBrush" Color="White" />
     <SolidColorBrush x:Key="ListBoxItemSelectedForegroundThemeBrush" Color="White" />
     <SolidColorBrush x:Key="ListBoxItemSelectedPointerOverBackgroundThemeBrush" Color="#FF5F37BE" />
     <SolidColorBrush x:Key="ListBoxItemSelectedPointerOverBackgroundThemeBrush" Color="#FF5F37BE" />
 
 
+    <!-- Resources for MenuFlyout.xaml (Menu, ContextMenu, etc) -->
+    <x:Double x:Key="MenuFlyoutSeparatorThemeHeight">1</x:Double>
+    <x:Double x:Key="MenuFlyoutThemeMinHeight">32</x:Double>
+    <Thickness x:Key="MenuFlyoutPresenterThemePadding">0,0</Thickness>
+    <!--<Thickness x:Key="MenuFlyoutItemCheckGlyphMargin">12,11,0,13</Thickness>-->
+    <Thickness x:Key="MenuFlyoutItemChevronMargin">12,0,0,0</Thickness>
+    <!--<Thickness x:Key="MenuFlyoutItemPlaceholderThemeThickness">28,0,0,0</Thickness>-->
+    <Thickness x:Key="MenuFlyoutSeparatorThemePadding">12,4,12,4</Thickness>
+    <StaticResource x:Key="MenuFlyoutItemBackground" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="MenuFlyoutItemBackgroundPointerOver" ResourceKey="SystemControlHighlightListLowBrush" />
+    <StaticResource x:Key="MenuFlyoutItemBackgroundPressed" ResourceKey="SystemControlHighlightListMediumBrush" />
+    <StaticResource x:Key="MenuFlyoutItemBackgroundDisabled" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="MenuFlyoutItemForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
+    <StaticResource x:Key="MenuFlyoutItemForegroundPointerOver" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
+    <StaticResource x:Key="MenuFlyoutItemForegroundPressed" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
+    <StaticResource x:Key="MenuFlyoutItemForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
+    <!--<StaticResource x:Key="MenuFlyoutSubItemBackground" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemBackgroundPointerOver" ResourceKey="SystemControlHighlightListLowBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemBackgroundPressed" ResourceKey="SystemControlHighlightListAccentHighBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemBackgroundSubMenuOpened" ResourceKey="SystemControlHighlightListLowBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemBackgroundDisabled" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemForegroundPointerOver" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemForegroundPressed" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemForegroundSubMenuOpened" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />-->
+    <StaticResource x:Key="MenuFlyoutSubItemChevron" ResourceKey="SystemControlForegroundBaseMediumHighBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemChevronPointerOver" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemChevronPressed" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemChevronSubMenuOpened" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemChevronDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
+    <StaticResource x:Key="MenuFlyoutLightDismissOverlayBackground" ResourceKey="SystemControlPageBackgroundMediumAltMediumBrush" />
+    <!--<SolidColorBrush x:Key="MenuFlyoutItemFocusedBackgroundThemeBrush" Color="#FF212121" />
+    <SolidColorBrush x:Key="MenuFlyoutItemFocusedForegroundThemeBrush" Color="#FFFFFFFF" />
+    <SolidColorBrush x:Key="MenuFlyoutItemDisabledForegroundThemeBrush" Color="#66FFFFFF" />
+    <SolidColorBrush x:Key="MenuFlyoutItemPointerOverBackgroundThemeBrush" Color="#FF212121" />
+    <SolidColorBrush x:Key="MenuFlyoutItemPointerOverForegroundThemeBrush" Color="#FFFFFFFF" />
+    <SolidColorBrush x:Key="MenuFlyoutItemPressedBackgroundThemeBrush" Color="#FFFFFFFF" />
+    <SolidColorBrush x:Key="MenuFlyoutItemPressedForegroundThemeBrush" Color="#FF000000" />-->
+    <!--<SolidColorBrush x:Key="MenuFlyoutSeparatorThemeBrush" Color="#FF7A7A7A" />-->
+    <!--<Thickness x:Key="MenuFlyoutItemDoublePlaceholderThemeThickness">56,0,0,0</Thickness>-->
+    <StaticResource x:Key="MenuFlyoutItemKeyboardAcceleratorTextForeground" ResourceKey="SystemControlForegroundBaseMediumBrush" />
+    <StaticResource x:Key="MenuFlyoutItemKeyboardAcceleratorTextForegroundPointerOver" ResourceKey="SystemControlHighlightAltBaseMediumBrush" />
+    <StaticResource x:Key="MenuFlyoutItemKeyboardAcceleratorTextForegroundPressed" ResourceKey="SystemControlHighlightAltBaseMediumBrush" />
+    <StaticResource x:Key="MenuFlyoutItemKeyboardAcceleratorTextForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
+    <Thickness x:Key="MenuFlyoutItemThemePadding">11,9,11,10</Thickness>
+    <Thickness x:Key="MenuFlyoutItemThemePaddingNarrow">11,4,11,7</Thickness>
+    <StaticResource x:Key="MenuFlyoutPresenterBackground" ResourceKey="SystemControlTransientBackgroundBrush" />
+    <StaticResource x:Key="MenuFlyoutPresenterBorderBrush" ResourceKey="SystemControlTransientBorderBrush" />
+    <Thickness x:Key="MenuFlyoutPresenterBorderThemeThickness">1</Thickness>
+    <!-- Resources for MenuFlyoutItem -->
+    <!--
+    <StaticResource x:Key="MenuFlyoutItemRevealBackground" ResourceKey="SystemControlTransparentRevealBackgroundBrush" />
+    <StaticResource x:Key="MenuFlyoutItemRevealBackgroundPointerOver" ResourceKey="SystemControlHighlightListLowRevealBackgroundBrush" />
+    <StaticResource x:Key="MenuFlyoutItemRevealBackgroundPressed" ResourceKey="SystemControlHighlightListMediumRevealBackgroundBrush" />
+    <StaticResource x:Key="MenuFlyoutItemRevealBackgroundDisabled" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="MenuFlyoutItemRevealBorderBrush" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="MenuFlyoutItemRevealBorderBrushPressed" ResourceKey="SystemControlTransparentRevealBorderBrush" />
+    <StaticResource x:Key="MenuFlyoutItemRevealBorderBrushPointerOver" ResourceKey="SystemControlTransparentRevealBorderBrush" />
+    <StaticResource x:Key="MenuFlyoutItemRevealBorderBrushDisabled" ResourceKey="SystemControlTransparentBrush" />
+    -->
+    <!-- Resources for ToggleMenuFlyoutItem -->
+    <!--
+    <StaticResource x:Key="ToggleMenuFlyoutItemRevealBackground" ResourceKey="SystemControlTransparentRevealBackgroundBrush" />
+    <StaticResource x:Key="ToggleMenuFlyoutItemRevealBackgroundPointerOver" ResourceKey="SystemControlHighlightListLowRevealBackgroundBrush" />
+    <StaticResource x:Key="ToggleMenuFlyoutItemRevealBackgroundPressed" ResourceKey="SystemControlHighlightListMediumRevealBackgroundBrush" />
+    <StaticResource x:Key="ToggleMenuFlyoutItemRevealBackgroundDisabled" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="ToggleMenuFlyoutItemRevealBorderBrush" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="ToggleMenuFlyoutItemRevealBorderBrushPressed" ResourceKey="SystemControlTransparentRevealBorderBrush" />
+    <StaticResource x:Key="ToggleMenuFlyoutItemRevealBorderBrushPointerOver" ResourceKey="SystemControlTransparentRevealBorderBrush" />
+    <StaticResource x:Key="ToggleMenuFlyoutItemRevealBorderBrushDisabled" ResourceKey="SystemControlTransparentBrush" />
+    -->
+    <!-- Resources for MenuFlyoutSubItem -->
+    <!--
+    <StaticResource x:Key="MenuFlyoutSubItemRevealBackground" ResourceKey="SystemControlTransparentRevealBackgroundBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemRevealBackgroundPointerOver" ResourceKey="SystemControlHighlightListLowRevealBackgroundBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemRevealBackgroundPressed" ResourceKey="SystemControlHighlightAccentRevealBackgroundBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemRevealBackgroundSubMenuOpened" ResourceKey="SystemControlHighlightListLowRevealBackgroundBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemRevealBackgroundDisabled" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemRevealBorderBrush" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemRevealBorderBrushPressed" ResourceKey="SystemControlTransparentRevealBorderBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemRevealBorderBrushPointerOver" ResourceKey="SystemControlTransparentRevealBorderBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemRevealBorderBrushSubMenuOpened" ResourceKey="SystemControlTransparentRevealBorderBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemRevealBorderBrushDisabled" ResourceKey="SystemControlTransparentBrush" />-->
+    <!--<Thickness x:Key="LanguageSwitcherMenuFlyoutItemPlaceholderThemeThickness">44,0,0,0</Thickness>-->
+
     <!-- Resources for TextBox.xaml -->
     <!-- Resources for TextBox.xaml -->
     <SolidColorBrush x:Key="TextBoxForegroundHeaderThemeBrush" Color="#FFFFFFFF" />
     <SolidColorBrush x:Key="TextBoxForegroundHeaderThemeBrush" Color="#FFFFFFFF" />
     <SolidColorBrush x:Key="TextBoxPlaceholderTextThemeBrush" Color="#AB000000" />
     <SolidColorBrush x:Key="TextBoxPlaceholderTextThemeBrush" Color="#AB000000" />
@@ -451,7 +537,7 @@
     <SolidColorBrush x:Key="RadioButtonPressedBorderThemeBrush" Color="#FFFFFFFF" />
     <SolidColorBrush x:Key="RadioButtonPressedBorderThemeBrush" Color="#FFFFFFFF" />
     <SolidColorBrush x:Key="RadioButtonPressedForegroundThemeBrush" Color="#FF000000" />
     <SolidColorBrush x:Key="RadioButtonPressedForegroundThemeBrush" Color="#FF000000" />
     <SolidColorBrush x:Key="RadioButtonContentPointerOverForegroundThemeBrush" Color="{DynamicResource SystemColorHighlightTextColor}" />
     <SolidColorBrush x:Key="RadioButtonContentPointerOverForegroundThemeBrush" Color="{DynamicResource SystemColorHighlightTextColor}" />
-    
+
     <!-- Resources for Slider.xaml -->
     <!-- Resources for Slider.xaml -->
     <x:Double x:Key="SliderOutsideTickBarThemeHeight">4</x:Double>
     <x:Double x:Key="SliderOutsideTickBarThemeHeight">4</x:Double>
     <x:Double x:Key="SliderTrackThemeHeight">2</x:Double>
     <x:Double x:Key="SliderTrackThemeHeight">2</x:Double>
@@ -502,6 +588,65 @@
     <SolidColorBrush x:Key="SliderTrackPressedBackgroundThemeBrush" Color="#59FFFFFF" />
     <SolidColorBrush x:Key="SliderTrackPressedBackgroundThemeBrush" Color="#59FFFFFF" />
     <SolidColorBrush x:Key="SliderHeaderForegroundThemeBrush" Color="#FFFFFFFF" />
     <SolidColorBrush x:Key="SliderHeaderForegroundThemeBrush" Color="#FFFFFFFF" />
 
 
+    <!--ToggleSwitch-->
+    <Thickness x:Key="ToggleSwitchOnStrokeThickness">0</Thickness>
+    <Thickness x:Key="ToggleSwitchOuterBorderStrokeThickness">1</Thickness>
+    <StaticResource x:Key="ToggleSwitchContentForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
+    <StaticResource x:Key="ToggleSwitchContentForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
+    <StaticResource x:Key="ToggleSwitchHeaderForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
+    <StaticResource x:Key="ToggleSwitchHeaderForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
+    <StaticResource x:Key="ToggleSwitchContainerBackground" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="ToggleSwitchContainerBackgroundPointerOver" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="ToggleSwitchContainerBackgroundPressed" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="ToggleSwitchContainerBackgroundDisabled" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="ToggleSwitchFillOff" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="ToggleSwitchFillOffPointerOver" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="ToggleSwitchFillOffPressed" ResourceKey="SystemControlHighlightBaseMediumLowBrush" />
+    <StaticResource x:Key="ToggleSwitchFillOffDisabled" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="ToggleSwitchStrokeOff" ResourceKey="SystemControlForegroundBaseMediumBrush" />
+    <StaticResource x:Key="ToggleSwitchStrokeOffPointerOver" ResourceKey="SystemControlHighlightBaseMediumHighBrush" />
+    <StaticResource x:Key="ToggleSwitchStrokeOffPressed" ResourceKey="SystemControlForegroundBaseHighBrush" />
+    <StaticResource x:Key="ToggleSwitchStrokeOffDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
+    <StaticResource x:Key="ToggleSwitchFillOn" ResourceKey="SystemControlHighlightAccentBrush" />
+    <StaticResource x:Key="ToggleSwitchFillOnPointerOver" ResourceKey="SystemAccentColorLight1" />
+    <StaticResource x:Key="ToggleSwitchFillOnPressed" ResourceKey="SystemAccentColorDark1" />
+    <StaticResource x:Key="ToggleSwitchFillOnDisabled" ResourceKey="SystemControlDisabledBaseLowBrush" />
+    <StaticResource x:Key="ToggleSwitchStrokeOn" ResourceKey="SystemControlHighlightBaseHighBrush" />
+    <StaticResource x:Key="ToggleSwitchStrokeOnPointerOver" ResourceKey="SystemAccentColorLight1" />
+    <StaticResource x:Key="ToggleSwitchStrokeOnPressed" ResourceKey="SystemAccentColorDark1" />
+    <StaticResource x:Key="ToggleSwitchStrokeOnDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
+    <StaticResource x:Key="ToggleSwitchKnobFillOff" ResourceKey="SystemControlHighlightBaseHighBrush" />
+    <StaticResource x:Key="ToggleSwitchKnobFillOffPointerOver" ResourceKey="SystemControlHighlightBaseHighBrush" />
+    <StaticResource x:Key="ToggleSwitchKnobFillOffPressed" ResourceKey="SystemControlHighlightBaseHighBrush" />
+    <StaticResource x:Key="ToggleSwitchKnobFillOffDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
+    <StaticResource x:Key="ToggleSwitchKnobFillOn" ResourceKey="SystemControlHighlightAltChromeWhiteBrush" />
+    <StaticResource x:Key="ToggleSwitchKnobFillOnPointerOver" ResourceKey="SystemControlHighlightChromeWhiteBrush" />
+    <StaticResource x:Key="ToggleSwitchKnobFillOnPressed" ResourceKey="SystemControlHighlightAltChromeWhiteBrush" />
+    <StaticResource x:Key="ToggleSwitchKnobFillOnDisabled" ResourceKey="SystemControlPageBackgroundBaseLowBrush" />
+    <SolidColorBrush x:Key="ToggleSwitchCurtainBackgroundThemeBrush" Color="#FF5729C1" />
+    <SolidColorBrush x:Key="ToggleSwitchCurtainDisabledBackgroundThemeBrush" Color="Transparent" />
+    <SolidColorBrush x:Key="ToggleSwitchCurtainPointerOverBackgroundThemeBrush" Color="#FF6E46CA" />
+    <SolidColorBrush x:Key="ToggleSwitchCurtainPressedBackgroundThemeBrush" Color="#FF7E4FEC" />
+    <SolidColorBrush x:Key="ToggleSwitchDisabledForegroundThemeBrush" Color="#66FFFFFF" />
+    <SolidColorBrush x:Key="ToggleSwitchForegroundThemeBrush" Color="#FFFFFFFF" />
+    <SolidColorBrush x:Key="ToggleSwitchHeaderDisabledForegroundThemeBrush" Color="#66FFFFFF" />
+    <SolidColorBrush x:Key="ToggleSwitchHeaderForegroundThemeBrush" Color="#FFFFFFFF" />
+    <SolidColorBrush x:Key="ToggleSwitchOuterBorderBorderThemeBrush" Color="#59FFFFFF" />
+    <SolidColorBrush x:Key="ToggleSwitchOuterBorderDisabledBorderThemeBrush" Color="#33FFFFFF" />
+    <SolidColorBrush x:Key="ToggleSwitchThumbBackgroundThemeBrush" Color="#FFFFFFFF" />
+    <SolidColorBrush x:Key="ToggleSwitchThumbBorderThemeBrush" Color="#FFFFFFFF" />
+    <SolidColorBrush x:Key="ToggleSwitchThumbDisabledBackgroundThemeBrush" Color="#FF7E7E7E" />
+    <SolidColorBrush x:Key="ToggleSwitchThumbDisabledBorderThemeBrush" Color="#FF7E7E7E" />
+    <SolidColorBrush x:Key="ToggleSwitchThumbPointerOverBackgroundThemeBrush" Color="#FFFFFFFF" />
+    <SolidColorBrush x:Key="ToggleSwitchThumbPointerOverBorderThemeBrush" Color="#FFFFFFFF" />
+    <SolidColorBrush x:Key="ToggleSwitchThumbPressedBackgroundThemeBrush" Color="#FFFFFFFF" />
+    <SolidColorBrush x:Key="ToggleSwitchThumbPressedForegroundThemeBrush" Color="#FFFFFFFF" />
+    <SolidColorBrush x:Key="ToggleSwitchTrackBackgroundThemeBrush" Color="#42FFFFFF" />
+    <SolidColorBrush x:Key="ToggleSwitchTrackBorderThemeBrush" Color="Transparent" />
+    <SolidColorBrush x:Key="ToggleSwitchTrackDisabledBackgroundThemeBrush" Color="#1FFFFFFF" />
+    <SolidColorBrush x:Key="ToggleSwitchTrackPointerOverBackgroundThemeBrush" Color="#4AFFFFFF" />
+    <SolidColorBrush x:Key="ToggleSwitchTrackPressedBackgroundThemeBrush" Color="#59FFFFFF" />
+
     <!-- Resources for ToolTip.xaml -->
     <!-- Resources for ToolTip.xaml -->
     <x:Double x:Key="ToolTipContentThemeFontSize">12</x:Double>
     <x:Double x:Key="ToolTipContentThemeFontSize">12</x:Double>
     <Thickness x:Key="ToolTipBorderThemeThickness">1</Thickness>
     <Thickness x:Key="ToolTipBorderThemeThickness">1</Thickness>

+ 150 - 6
src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesLight.xaml

@@ -1,5 +1,5 @@
-<Style xmlns="https://github.com/avaloniaui" 
-  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
+<Style xmlns="https://github.com/avaloniaui"
+  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:sys="clr-namespace:System;assembly=netstandard">
   xmlns:sys="clr-namespace:System;assembly=netstandard">
   <Style.Resources>
   <Style.Resources>
     <!-- Resources for Button.xaml -->
     <!-- Resources for Button.xaml -->
@@ -181,8 +181,8 @@
     <StaticResource x:Key="ComboBoxDropDownGlyphForeground" ResourceKey="SystemControlForegroundBaseMediumHighBrush" />
     <StaticResource x:Key="ComboBoxDropDownGlyphForeground" ResourceKey="SystemControlForegroundBaseMediumHighBrush" />
     <StaticResource x:Key="ComboBoxDropDownGlyphForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
     <StaticResource x:Key="ComboBoxDropDownGlyphForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
     <StaticResource x:Key="ComboBoxDropDownGlyphForegroundFocused" ResourceKey="SystemControlHighlightAltBaseMediumHighBrush" />
     <StaticResource x:Key="ComboBoxDropDownGlyphForegroundFocused" ResourceKey="SystemControlHighlightAltBaseMediumHighBrush" />
-    <StaticResource x:Key="ComboBoxDropDownGlyphForegroundFocusedPressed" ResourceKey="SystemControlHighlightAltBaseMediumHighBrush" />    
-    <StaticResource x:Key="ComboBoxDropDownForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />    
+    <StaticResource x:Key="ComboBoxDropDownGlyphForegroundFocusedPressed" ResourceKey="SystemControlHighlightAltBaseMediumHighBrush" />
+    <StaticResource x:Key="ComboBoxDropDownForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
     <StaticResource x:Key="ComboBoxDropDownBackground" ResourceKey="SystemControlTransientBackgroundBrush" />
     <StaticResource x:Key="ComboBoxDropDownBackground" ResourceKey="SystemControlTransientBackgroundBrush" />
     <StaticResource x:Key="ComboBoxDropDownBorderBrush" ResourceKey="SystemControlTransientBorderBrush" />
     <StaticResource x:Key="ComboBoxDropDownBorderBrush" ResourceKey="SystemControlTransientBorderBrush" />
 
 
@@ -230,7 +230,7 @@
     <StaticResource x:Key="ComboBoxFocusedDropDownBackgroundPointerOver" ResourceKey="SystemControlBackgroundBaseLowBrush" />
     <StaticResource x:Key="ComboBoxFocusedDropDownBackgroundPointerOver" ResourceKey="SystemControlBackgroundBaseLowBrush" />
     <StaticResource x:Key="ComboBoxFocusedDropDownBackgroundPointerPressed" ResourceKey="SystemControlBackgroundBaseMediumLowBrush" />
     <StaticResource x:Key="ComboBoxFocusedDropDownBackgroundPointerPressed" ResourceKey="SystemControlBackgroundBaseMediumLowBrush" />
     <StaticResource x:Key="ComboBoxEditableDropDownGlyphForeground" ResourceKey="SystemControlForegroundBaseMediumHighBrush" />
     <StaticResource x:Key="ComboBoxEditableDropDownGlyphForeground" ResourceKey="SystemControlForegroundBaseMediumHighBrush" />
-    
+
     <!-- Resources for ListBox.xaml -->
     <!-- Resources for ListBox.xaml -->
     <Thickness x:Key="ListBoxBorderThemeThickness">0</Thickness>
     <Thickness x:Key="ListBoxBorderThemeThickness">0</Thickness>
     <SolidColorBrush x:Key="ListBoxBackgroundThemeBrush" Color="#CCFFFFFF" />
     <SolidColorBrush x:Key="ListBoxBackgroundThemeBrush" Color="#CCFFFFFF" />
@@ -249,6 +249,91 @@
     <SolidColorBrush x:Key="ListBoxItemSelectedForegroundThemeBrush" Color="White" />
     <SolidColorBrush x:Key="ListBoxItemSelectedForegroundThemeBrush" Color="White" />
     <SolidColorBrush x:Key="ListBoxItemSelectedPointerOverBackgroundThemeBrush" Color="#FF5F37BE" />
     <SolidColorBrush x:Key="ListBoxItemSelectedPointerOverBackgroundThemeBrush" Color="#FF5F37BE" />
 
 
+    <!-- Resources for MenuFlyout.xaml (Menu, ContextMenu, etc) -->
+    <x:Double x:Key="MenuFlyoutSeparatorThemeHeight">1</x:Double>
+    <x:Double x:Key="MenuFlyoutThemeMinHeight">32</x:Double>
+    <Thickness x:Key="MenuFlyoutPresenterThemePadding">0,0</Thickness>
+    <!--<Thickness x:Key="MenuFlyoutItemCheckGlyphMargin">12,11,0,13</Thickness>-->
+    <Thickness x:Key="MenuFlyoutItemChevronMargin">12,0,0,0</Thickness>
+    <!--<Thickness x:Key="MenuFlyoutItemPlaceholderThemeThickness">28,0,0,0</Thickness>-->
+    <Thickness x:Key="MenuFlyoutSeparatorThemePadding">12,4,12,4</Thickness>
+    <StaticResource x:Key="MenuFlyoutItemBackground" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="MenuFlyoutItemBackgroundPointerOver" ResourceKey="SystemControlHighlightListLowBrush" />
+    <StaticResource x:Key="MenuFlyoutItemBackgroundPressed" ResourceKey="SystemControlHighlightListMediumBrush" />
+    <StaticResource x:Key="MenuFlyoutItemBackgroundDisabled" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="MenuFlyoutItemForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
+    <StaticResource x:Key="MenuFlyoutItemForegroundPointerOver" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
+    <StaticResource x:Key="MenuFlyoutItemForegroundPressed" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
+    <StaticResource x:Key="MenuFlyoutItemForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
+    <!--<StaticResource x:Key="MenuFlyoutSubItemBackground" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemBackgroundPointerOver" ResourceKey="SystemControlHighlightListLowBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemBackgroundPressed" ResourceKey="SystemControlHighlightListAccentHighBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemBackgroundSubMenuOpened" ResourceKey="SystemControlHighlightListLowBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemBackgroundDisabled" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemForegroundPointerOver" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemForegroundPressed" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemForegroundSubMenuOpened" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />-->
+    <StaticResource x:Key="MenuFlyoutSubItemChevron" ResourceKey="SystemControlForegroundBaseMediumHighBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemChevronPointerOver" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemChevronPressed" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemChevronSubMenuOpened" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemChevronDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
+    <StaticResource x:Key="MenuFlyoutLightDismissOverlayBackground" ResourceKey="SystemControlPageBackgroundMediumAltMediumBrush" />
+    <!--<SolidColorBrush x:Key="MenuFlyoutItemFocusedBackgroundThemeBrush" Color="#FFE5E5E5" />
+    <SolidColorBrush x:Key="MenuFlyoutItemFocusedForegroundThemeBrush" Color="#FF000000" />
+    <SolidColorBrush x:Key="MenuFlyoutItemDisabledForegroundThemeBrush" Color="#66000000" />
+    <SolidColorBrush x:Key="MenuFlyoutItemPointerOverBackgroundThemeBrush" Color="#FFE5E5E5" />
+    <SolidColorBrush x:Key="MenuFlyoutItemPointerOverForegroundThemeBrush" Color="#FF000000" />
+    <SolidColorBrush x:Key="MenuFlyoutItemPressedBackgroundThemeBrush" Color="#FF000000" />
+    <SolidColorBrush x:Key="MenuFlyoutItemPressedForegroundThemeBrush" Color="#FFFFFFFF" />
+    <SolidColorBrush x:Key="MenuFlyoutSeparatorThemeBrush" Color="#FF7A7A7A" />-->
+    <!--<Thickness x:Key="MenuFlyoutItemDoublePlaceholderThemeThickness">56,0,0,0</Thickness>-->
+    <StaticResource x:Key="MenuFlyoutItemKeyboardAcceleratorTextForeground" ResourceKey="SystemControlForegroundBaseMediumBrush" />
+    <StaticResource x:Key="MenuFlyoutItemKeyboardAcceleratorTextForegroundPointerOver" ResourceKey="SystemControlHighlightAltBaseMediumBrush" />
+    <StaticResource x:Key="MenuFlyoutItemKeyboardAcceleratorTextForegroundPressed" ResourceKey="SystemControlHighlightAltBaseMediumBrush" />
+    <StaticResource x:Key="MenuFlyoutItemKeyboardAcceleratorTextForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
+    <Thickness x:Key="MenuFlyoutItemThemePadding">11,9,11,10</Thickness>
+    <Thickness x:Key="MenuFlyoutItemThemePaddingNarrow">11,4,11,7</Thickness>
+    <StaticResource x:Key="MenuFlyoutPresenterBackground" ResourceKey="SystemControlTransientBackgroundBrush" />
+    <StaticResource x:Key="MenuFlyoutPresenterBorderBrush" ResourceKey="SystemControlTransientBorderBrush" />
+    <Thickness x:Key="MenuFlyoutPresenterBorderThemeThickness">1</Thickness>
+    <!-- Resources for MenuFlyoutItem -->
+    <!--<StaticResource x:Key="MenuFlyoutItemRevealBackground" ResourceKey="SystemControlTransparentRevealBackgroundBrush" />
+    <StaticResource x:Key="MenuFlyoutItemRevealBackgroundPointerOver" ResourceKey="SystemControlHighlightListLowRevealBackgroundBrush" />
+    <StaticResource x:Key="MenuFlyoutItemRevealBackgroundPressed" ResourceKey="SystemControlHighlightListMediumRevealBackgroundBrush" />
+    <StaticResource x:Key="MenuFlyoutItemRevealBackgroundDisabled" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="MenuFlyoutItemRevealBorderBrush" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="MenuFlyoutItemRevealBorderBrushPressed" ResourceKey="SystemControlTransparentRevealBorderBrush" />
+    <StaticResource x:Key="MenuFlyoutItemRevealBorderBrushPointerOver" ResourceKey="SystemControlTransparentRevealBorderBrush" />
+    <StaticResource x:Key="MenuFlyoutItemRevealBorderBrushDisabled" ResourceKey="SystemControlTransparentBrush" />
+    -->
+    <!-- Resources for ToggleMenuFlyoutItem -->
+    <!--
+    <StaticResource x:Key="ToggleMenuFlyoutItemRevealBackground" ResourceKey="SystemControlTransparentRevealBackgroundBrush" />
+    <StaticResource x:Key="ToggleMenuFlyoutItemRevealBackgroundPointerOver" ResourceKey="SystemControlHighlightListLowRevealBackgroundBrush" />
+    <StaticResource x:Key="ToggleMenuFlyoutItemRevealBackgroundPressed" ResourceKey="SystemControlHighlightListMediumRevealBackgroundBrush" />
+    <StaticResource x:Key="ToggleMenuFlyoutItemRevealBackgroundDisabled" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="ToggleMenuFlyoutItemRevealBorderBrush" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="ToggleMenuFlyoutItemRevealBorderBrushPressed" ResourceKey="SystemControlTransparentRevealBorderBrush" />
+    <StaticResource x:Key="ToggleMenuFlyoutItemRevealBorderBrushPointerOver" ResourceKey="SystemControlTransparentRevealBorderBrush" />
+    <StaticResource x:Key="ToggleMenuFlyoutItemRevealBorderBrushDisabled" ResourceKey="SystemControlTransparentBrush" />
+    -->
+    <!-- Resources for MenuFlyoutSubItem -->
+    <!--
+    <StaticResource x:Key="MenuFlyoutSubItemRevealBackground" ResourceKey="SystemControlTransparentRevealBackgroundBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemRevealBackgroundPointerOver" ResourceKey="SystemControlHighlightListLowRevealBackgroundBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemRevealBackgroundPressed" ResourceKey="SystemControlHighlightAccentRevealBackgroundBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemRevealBackgroundSubMenuOpened" ResourceKey="SystemControlHighlightListLowRevealBackgroundBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemRevealBackgroundDisabled" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemRevealBorderBrush" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemRevealBorderBrushPressed" ResourceKey="SystemControlTransparentRevealBorderBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemRevealBorderBrushPointerOver" ResourceKey="SystemControlTransparentRevealBorderBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemRevealBorderBrushSubMenuOpened" ResourceKey="SystemControlTransparentRevealBorderBrush" />
+    <StaticResource x:Key="MenuFlyoutSubItemRevealBorderBrushDisabled" ResourceKey="SystemControlTransparentBrush" />
+    <Thickness x:Key="LanguageSwitcherMenuFlyoutItemPlaceholderThemeThickness">44,0,0,0</Thickness>-->
+
     <!-- Resources for TextBox.xaml -->
     <!-- Resources for TextBox.xaml -->
     <SolidColorBrush x:Key="TextBoxForegroundHeaderThemeBrush" Color="#FF000000" />
     <SolidColorBrush x:Key="TextBoxForegroundHeaderThemeBrush" Color="#FF000000" />
     <SolidColorBrush x:Key="TextBoxPlaceholderTextThemeBrush" Color="#AB000000" />
     <SolidColorBrush x:Key="TextBoxPlaceholderTextThemeBrush" Color="#AB000000" />
@@ -450,7 +535,7 @@
     <SolidColorBrush x:Key="RadioButtonPressedBorderThemeBrush" Color="#FF000000" />
     <SolidColorBrush x:Key="RadioButtonPressedBorderThemeBrush" Color="#FF000000" />
     <SolidColorBrush x:Key="RadioButtonPressedForegroundThemeBrush" Color="#FFFFFFFF" />
     <SolidColorBrush x:Key="RadioButtonPressedForegroundThemeBrush" Color="#FFFFFFFF" />
     <SolidColorBrush x:Key="RadioButtonContentPointerOverForegroundThemeBrush" Color="{DynamicResource SystemColorHighlightTextColor}" />
     <SolidColorBrush x:Key="RadioButtonContentPointerOverForegroundThemeBrush" Color="{DynamicResource SystemColorHighlightTextColor}" />
-    
+
     <!-- Resources for Slider.xaml -->
     <!-- Resources for Slider.xaml -->
     <x:Double x:Key="SliderOutsideTickBarThemeHeight">4</x:Double>
     <x:Double x:Key="SliderOutsideTickBarThemeHeight">4</x:Double>
     <x:Double x:Key="SliderTrackThemeHeight">2</x:Double>
     <x:Double x:Key="SliderTrackThemeHeight">2</x:Double>
@@ -501,6 +586,65 @@
     <SolidColorBrush x:Key="SliderTrackPressedBackgroundThemeBrush" Color="#33000000" />
     <SolidColorBrush x:Key="SliderTrackPressedBackgroundThemeBrush" Color="#33000000" />
     <SolidColorBrush x:Key="SliderHeaderForegroundThemeBrush" Color="#FF000000" />
     <SolidColorBrush x:Key="SliderHeaderForegroundThemeBrush" Color="#FF000000" />
 
 
+    <!--Recources ToggleSwitch-->
+    <Thickness x:Key="ToggleSwitchOnStrokeThickness">0</Thickness>
+    <Thickness x:Key="ToggleSwitchOuterBorderStrokeThickness">1</Thickness>
+    <StaticResource x:Key="ToggleSwitchContentForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
+    <StaticResource x:Key="ToggleSwitchContentForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
+    <StaticResource x:Key="ToggleSwitchHeaderForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
+    <StaticResource x:Key="ToggleSwitchHeaderForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
+    <StaticResource x:Key="ToggleSwitchContainerBackground" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="ToggleSwitchContainerBackgroundPointerOver" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="ToggleSwitchContainerBackgroundPressed" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="ToggleSwitchContainerBackgroundDisabled" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="ToggleSwitchFillOff" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="ToggleSwitchFillOffPointerOver" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="ToggleSwitchFillOffPressed" ResourceKey="SystemControlHighlightBaseMediumLowBrush" />
+    <StaticResource x:Key="ToggleSwitchFillOffDisabled" ResourceKey="SystemControlTransparentBrush" />
+    <StaticResource x:Key="ToggleSwitchStrokeOff" ResourceKey="SystemControlForegroundBaseMediumBrush" />
+    <StaticResource x:Key="ToggleSwitchStrokeOffPointerOver" ResourceKey="SystemControlHighlightBaseMediumHighBrush" />
+    <StaticResource x:Key="ToggleSwitchStrokeOffPressed" ResourceKey="SystemControlForegroundBaseHighBrush" />
+    <StaticResource x:Key="ToggleSwitchStrokeOffDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
+    <StaticResource x:Key="ToggleSwitchFillOn" ResourceKey="SystemControlHighlightAccentBrush" />
+    <StaticResource x:Key="ToggleSwitchFillOnPointerOver" ResourceKey="SystemAccentColorLight1" />
+    <StaticResource x:Key="ToggleSwitchFillOnPressed" ResourceKey="SystemAccentColorDark1" />
+    <StaticResource x:Key="ToggleSwitchFillOnDisabled" ResourceKey="SystemControlDisabledBaseLowBrush" />
+    <StaticResource x:Key="ToggleSwitchStrokeOn" ResourceKey="SystemControlHighlightBaseHighBrush" />
+    <StaticResource x:Key="ToggleSwitchStrokeOnPointerOver" ResourceKey="SystemControlHighlightListAccentHighBrush" />
+    <StaticResource x:Key="ToggleSwitchStrokeOnPressed" ResourceKey="SystemControlHighlightBaseMediumBrush" />
+    <StaticResource x:Key="ToggleSwitchStrokeOnDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
+    <StaticResource x:Key="ToggleSwitchKnobFillOff" ResourceKey="SystemControlForegroundBaseHighBrush" />
+    <StaticResource x:Key="ToggleSwitchKnobFillOffPointerOver" ResourceKey="SystemControlHighlightBaseHighBrush" />
+    <StaticResource x:Key="ToggleSwitchKnobFillOffPressed" ResourceKey="SystemControlHighlightBaseHighBrush" />
+    <StaticResource x:Key="ToggleSwitchKnobFillOffDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
+    <StaticResource x:Key="ToggleSwitchKnobFillOn" ResourceKey="SystemControlHighlightAltChromeWhiteBrush" />
+    <StaticResource x:Key="ToggleSwitchKnobFillOnPointerOver" ResourceKey="SystemControlHighlightChromeWhiteBrush" />
+    <StaticResource x:Key="ToggleSwitchKnobFillOnPressed" ResourceKey="SystemControlHighlightAltChromeWhiteBrush" />
+    <StaticResource x:Key="ToggleSwitchKnobFillOnDisabled" ResourceKey="SystemControlPageBackgroundBaseLowBrush" />
+    <SolidColorBrush x:Key="ToggleSwitchCurtainBackgroundThemeBrush" Color="#FF4617B4" />
+    <SolidColorBrush x:Key="ToggleSwitchCurtainDisabledBackgroundThemeBrush" Color="Transparent" />
+    <SolidColorBrush x:Key="ToggleSwitchCurtainPointerOverBackgroundThemeBrush" Color="#FF5F37BE" />
+    <SolidColorBrush x:Key="ToggleSwitchCurtainPressedBackgroundThemeBrush" Color="#FF7241E4" />
+    <SolidColorBrush x:Key="ToggleSwitchDisabledForegroundThemeBrush" Color="#66000000" />
+    <SolidColorBrush x:Key="ToggleSwitchForegroundThemeBrush" Color="#FF000000" />
+    <SolidColorBrush x:Key="ToggleSwitchHeaderDisabledForegroundThemeBrush" Color="#66000000" />
+    <SolidColorBrush x:Key="ToggleSwitchHeaderForegroundThemeBrush" Color="#FF000000" />
+    <SolidColorBrush x:Key="ToggleSwitchOuterBorderBorderThemeBrush" Color="#59000000" />
+    <SolidColorBrush x:Key="ToggleSwitchOuterBorderDisabledBorderThemeBrush" Color="#33000000" />
+    <SolidColorBrush x:Key="ToggleSwitchThumbBackgroundThemeBrush" Color="#FF000000" />
+    <SolidColorBrush x:Key="ToggleSwitchThumbBorderThemeBrush" Color="#FF000000" />
+    <SolidColorBrush x:Key="ToggleSwitchThumbDisabledBackgroundThemeBrush" Color="#FF929292" />
+    <SolidColorBrush x:Key="ToggleSwitchThumbDisabledBorderThemeBrush" Color="#FF929292" />
+    <SolidColorBrush x:Key="ToggleSwitchThumbPointerOverBackgroundThemeBrush" Color="#FF000000" />
+    <SolidColorBrush x:Key="ToggleSwitchThumbPointerOverBorderThemeBrush" Color="#FF000000" />
+    <SolidColorBrush x:Key="ToggleSwitchThumbPressedBackgroundThemeBrush" Color="#FF000000" />
+    <SolidColorBrush x:Key="ToggleSwitchThumbPressedForegroundThemeBrush" Color="#FF000000" />
+    <SolidColorBrush x:Key="ToggleSwitchTrackBackgroundThemeBrush" Color="#59000000" />
+    <SolidColorBrush x:Key="ToggleSwitchTrackBorderThemeBrush" Color="Transparent" />
+    <SolidColorBrush x:Key="ToggleSwitchTrackDisabledBackgroundThemeBrush" Color="#1F000000" />
+    <SolidColorBrush x:Key="ToggleSwitchTrackPointerOverBackgroundThemeBrush" Color="#4A000000" />
+    <SolidColorBrush x:Key="ToggleSwitchTrackPressedBackgroundThemeBrush" Color="#42000000" />
+
     <!-- Resources for ToolTip.xaml -->
     <!-- Resources for ToolTip.xaml -->
     <x:Double x:Key="ToolTipContentThemeFontSize">12</x:Double>
     <x:Double x:Key="ToolTipContentThemeFontSize">12</x:Double>
     <Thickness x:Key="ToolTipBorderThemeThickness">1</Thickness>
     <Thickness x:Key="ToolTipBorderThemeThickness">1</Thickness>

+ 6 - 0
src/Avalonia.Themes.Fluent/Common.xaml

@@ -0,0 +1,6 @@
+<Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+  <Style Selector="TextBlock.CaptionTextBlockStyle">
+    <Setter Property="FontSize" Value="12" />
+    <Setter Property="FontWeight" Value="Normal" />
+  </Style>
+</Styles>

+ 54 - 15
src/Avalonia.Themes.Fluent/ContextMenu.xaml

@@ -1,22 +1,61 @@
-<Style xmlns="https://github.com/avaloniaui" Selector="ContextMenu">
-    <Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/>
-    <Setter Property="BorderThickness" Value="1"/>
-    <Setter Property="Padding" Value="4,2"/>
-    <Setter Property="TextBlock.FontSize" Value="{DynamicResource FontSizeNormal}" />
-    <Setter Property="TextBlock.FontWeight" Value="Normal" />
-    <Setter Property="Template">
+<Style xmlns="https://github.com/avaloniaui"
+       Selector="ContextMenu">
+  <Design.PreviewWith>
+    <Border Background="{DynamicResource ThemeAccentBrush}"
+            Margin="16"
+            Padding="48"
+            Width="400"
+            Height="200">
+      <Border.ContextMenu>
+        <ContextMenu>
+          <MenuItem Header="Standard _Menu Item" />
+          <Separator />
+          <MenuItem Header="Menu with _Submenu">
+            <MenuItem Header="Submenu _1" />
+            <MenuItem Header="Submenu _2" />
+          </MenuItem>
+          <MenuItem Header="Menu Item with _Icon" />
+          <MenuItem Header="Menu Item with _Checkbox">
+            <MenuItem.Icon>
+              <CheckBox BorderThickness="0"
+                        IsHitTestVisible="False"
+                        IsChecked="True" />
+            </MenuItem.Icon>
+          </MenuItem>
+        </ContextMenu>
+      </Border.ContextMenu>
+      <TextBlock Text="Defined in XAML" />
+    </Border>
+  </Design.PreviewWith>
+
+  <Setter Property="Background" Value="{DynamicResource MenuFlyoutPresenterBackground}" />
+  <Setter Property="BorderBrush" Value="{DynamicResource MenuFlyoutPresenterBorderBrush}" />
+  <Setter Property="BorderThickness" Value="{DynamicResource MenuFlyoutPresenterBorderThemeThickness}" />
+  <Setter Property="MaxWidth" Value="{DynamicResource FlyoutThemeMaxWidth}" />
+  <Setter Property="MinHeight" Value="{DynamicResource MenuFlyoutThemeMinHeight}" />
+  <Setter Property="Padding" Value="{DynamicResource MenuFlyoutPresenterThemePadding}" />
+  <Setter Property="HorizontalAlignment" Value="Stretch" />
+  <Setter Property="TextBlock.FontSize" Value="{DynamicResource FontSizeNormal}" />
+  <Setter Property="TextBlock.FontWeight" Value="Normal" />
+  <Setter Property="Template">
     <ControlTemplate>
     <ControlTemplate>
       <Border Background="{TemplateBinding Background}"
       <Border Background="{TemplateBinding Background}"
               BorderBrush="{TemplateBinding BorderBrush}"
               BorderBrush="{TemplateBinding BorderBrush}"
               BorderThickness="{TemplateBinding BorderThickness}"
               BorderThickness="{TemplateBinding BorderThickness}"
-              Padding="{TemplateBinding Padding}">
-          <ScrollViewer>
-              <ItemsPresenter Name="PART_ItemsPresenter"
-                              Items="{TemplateBinding Items}"
-                              ItemsPanel="{TemplateBinding ItemsPanel}"
-                              ItemTemplate="{TemplateBinding ItemTemplate}"
-                              KeyboardNavigation.TabNavigation="Continue"/>
-          </ScrollViewer>
+              Padding="{TemplateBinding Padding}"
+              MaxWidth="{TemplateBinding MaxWidth}"
+              MinHeight="{TemplateBinding MinHeight}"
+              HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
+              CornerRadius="{DynamicResource OverlayCornerRadius}">
+        <ScrollViewer>
+          <ItemsPresenter Name="PART_ItemsPresenter"
+                          Items="{TemplateBinding Items}"
+                          ItemsPanel="{TemplateBinding ItemsPanel}"
+                          ItemTemplate="{TemplateBinding ItemTemplate}"
+                          Margin="{DynamicResource MenuFlyoutScrollerMargin}"
+                          KeyboardNavigation.TabNavigation="Continue"
+                          Grid.IsSharedSizeScope="True" />
+        </ScrollViewer>
       </Border>
       </Border>
     </ControlTemplate>
     </ControlTemplate>
   </Setter>
   </Setter>

+ 1 - 0
src/Avalonia.Themes.Fluent/FluentTheme.xaml

@@ -52,4 +52,5 @@
   <StyleInclude Source="resm:Avalonia.Themes.Fluent.WindowNotificationManager.xaml?assembly=Avalonia.Themes.Fluent"/>
   <StyleInclude Source="resm:Avalonia.Themes.Fluent.WindowNotificationManager.xaml?assembly=Avalonia.Themes.Fluent"/>
   <StyleInclude Source="resm:Avalonia.Themes.Fluent.NotificationCard.xaml?assembly=Avalonia.Themes.Fluent"/>
   <StyleInclude Source="resm:Avalonia.Themes.Fluent.NotificationCard.xaml?assembly=Avalonia.Themes.Fluent"/>
   <StyleInclude Source="resm:Avalonia.Themes.Fluent.NativeMenuBar.xaml?assembly=Avalonia.Themes.Fluent"/>
   <StyleInclude Source="resm:Avalonia.Themes.Fluent.NativeMenuBar.xaml?assembly=Avalonia.Themes.Fluent"/>
+  <StyleInclude Source="resm:Avalonia.Themes.Fluent.ToggleSwitch.xaml?assembly=Avalonia.Themes.Fluent"/>
 </Styles>
 </Styles>

+ 23 - 5
src/Avalonia.Themes.Fluent/Menu.xaml

@@ -1,16 +1,34 @@
-<Style xmlns="https://github.com/avaloniaui" Selector="Menu">
+<Style xmlns="https://github.com/avaloniaui"
+       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+       Selector="Menu">
+  <Design.PreviewWith>
+    <Border Padding="20">
+      <Menu>
+        <MenuItem Header="New" />
+        <MenuItem Header="Open" />
+      </Menu>
+    </Border>
+  </Design.PreviewWith>
+
+  <Style.Resources>
+    <x:Double x:Key="MenuHeight">32</x:Double>
+  </Style.Resources>
+  <Setter Property="Background" Value="Transparent" />
+  <Setter Property="Height" Value="{StaticResource MenuHeight}" />
   <Setter Property="Template">
   <Setter Property="Template">
     <ControlTemplate>
     <ControlTemplate>
       <Border Background="{TemplateBinding Background}"
       <Border Background="{TemplateBinding Background}"
               BorderBrush="{TemplateBinding BorderBrush}"
               BorderBrush="{TemplateBinding BorderBrush}"
               BorderThickness="{TemplateBinding BorderThickness}"
               BorderThickness="{TemplateBinding BorderThickness}"
+              HorizontalAlignment="Stretch"
               Padding="{TemplateBinding Padding}">
               Padding="{TemplateBinding Padding}">
-        <ItemsPresenter Name="PART_ItemsPresenter" 
-                        Items="{TemplateBinding Items}" 
+        <ItemsPresenter Name="PART_ItemsPresenter"
+                        Items="{TemplateBinding Items}"
                         ItemsPanel="{TemplateBinding ItemsPanel}"
                         ItemsPanel="{TemplateBinding ItemsPanel}"
                         ItemTemplate="{TemplateBinding ItemTemplate}"
                         ItemTemplate="{TemplateBinding ItemTemplate}"
-                        KeyboardNavigation.TabNavigation="Continue"/>
+                        VerticalAlignment="Stretch"
+                        KeyboardNavigation.TabNavigation="Continue" />
       </Border>
       </Border>
     </ControlTemplate>
     </ControlTemplate>
   </Setter>
   </Setter>
-</Style>
+</Style>

+ 178 - 66
src/Avalonia.Themes.Fluent/MenuItem.xaml

@@ -2,98 +2,143 @@
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:conv="clr-namespace:Avalonia.Controls.Converters;assembly=Avalonia.Controls"
         xmlns:conv="clr-namespace:Avalonia.Controls.Converters;assembly=Avalonia.Controls"
         xmlns:sys="clr-namespace:System;assembly=netstandard">
         xmlns:sys="clr-namespace:System;assembly=netstandard">
+  <Design.PreviewWith>
+    <Border Padding="20"
+            Width="400"
+            Height="200">
+      <Menu VerticalAlignment="Top">
+        <MenuItem Header="File">
+          <MenuItem Header="New"
+                    InputGesture="Ctrl+N">
+            <MenuItem Header="XML" />
+          </MenuItem>
+          <MenuItem Header="Open">
+            <MenuItem.Icon>
+              <CheckBox BorderThickness="0"
+                        IsHitTestVisible="False"
+                        IsChecked="True" />
+            </MenuItem.Icon>
+          </MenuItem>
+          <Separator />
+          <MenuItem Header="Exit"
+                    InputGesture="Alt+F4" />
+        </MenuItem>
+        <MenuItem Header="Edit">
+          <MenuItem Header="Go To">
+            <MenuItem Header="Go To Line"/>
+          </MenuItem>
+        </MenuItem>
+        <MenuItem Header="View">
+          <MenuItem Header="Designer" InputGesture="Shift+F7" />
+        </MenuItem>
+        <MenuItem Header="Project">
+          <MenuItem Header="Add class" />
+        </MenuItem>
+      </Menu>
+    </Border>
+  </Design.PreviewWith>
+
   <Styles.Resources>
   <Styles.Resources>
-    <conv:PlatformKeyGestureConverter x:Key="KeyGestureConverter"/>
+    <conv:PlatformKeyGestureConverter x:Key="KeyGestureConverter" />
+    <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>    
+    <StreamGeometry x:Key="MenuItemChevronPathData">M 1,0 10,10 l -9,10 -1,-1 L 8,10 -0,1 Z</StreamGeometry>
   </Styles.Resources>
   </Styles.Resources>
+
   <Style Selector="MenuItem">
   <Style Selector="MenuItem">
-    <Setter Property="Background" Value="Transparent"/>
-    <Setter Property="BorderThickness" Value="1"/>
-    <Setter Property="Padding" Value="6 0"/>
+    <Setter Property="Background" Value="{DynamicResource MenuFlyoutItemBackground}" />
+    <Setter Property="BorderBrush" Value="{DynamicResource MenuFlyoutItemRevealBorderBrush}" />
+    <Setter Property="Foreground" Value="{DynamicResource MenuFlyoutItemForeground}" />
+    <Setter Property="Padding" Value="{DynamicResource MenuFlyoutItemThemePadding}" />
+    <Setter Property="FontSize" Value="{DynamicResource ControlContentThemeFontSize}" />
     <Setter Property="Template">
     <Setter Property="Template">
       <ControlTemplate>
       <ControlTemplate>
-        <Border Name="root"
+        <Border Name="PART_LayoutRoot"
+                Padding="{TemplateBinding Padding}"
                 Background="{TemplateBinding Background}"
                 Background="{TemplateBinding Background}"
                 BorderBrush="{TemplateBinding BorderBrush}"
                 BorderBrush="{TemplateBinding BorderBrush}"
                 BorderThickness="{TemplateBinding BorderThickness}">
                 BorderThickness="{TemplateBinding BorderThickness}">
           <Grid>
           <Grid>
             <Grid.ColumnDefinitions>
             <Grid.ColumnDefinitions>
-              <ColumnDefinition Width="20"/>
-              <ColumnDefinition Width="5"/>
-              <ColumnDefinition Width="*"/>
-              <ColumnDefinition Width="Auto" SharedSizeGroup="MenuItemIGT"/>
-              <ColumnDefinition Width="20"/>
+              <ColumnDefinition Width="Auto"
+                                SharedSizeGroup="MenuItemIcon"  />
+              <ColumnDefinition Width="*" />
+              <ColumnDefinition Width="Auto"
+                                SharedSizeGroup="MenuItemIGT" />
+              <ColumnDefinition Width="Auto"
+                                SharedSizeGroup="MenuItemChevron" />
             </Grid.ColumnDefinitions>
             </Grid.ColumnDefinitions>
-            <ContentPresenter Name="icon"
+            <ContentPresenter Name="PART_IconPresenter"
                               Content="{TemplateBinding Icon}"
                               Content="{TemplateBinding Icon}"
                               Width="16"
                               Width="16"
                               Height="16"
                               Height="16"
-                              Margin="3"
+                              Margin="{DynamicResource MenuIconPresenterMargin}"
                               HorizontalAlignment="Center"
                               HorizontalAlignment="Center"
                               VerticalAlignment="Center"/>
                               VerticalAlignment="Center"/>
-            <Path Name="check"
-                  Fill="{TemplateBinding Foreground}"
-                  Data="F1M10,1.2L4.7,9.1 4.5,9.1 0,5.2 1.3,3.5 4.3,6.1 8.3,0 10,1.2z"
-                  IsVisible="False"
-                  Margin="3"
-                  VerticalAlignment="Center"/>
+
             <ContentPresenter Name="PART_HeaderPresenter"
             <ContentPresenter Name="PART_HeaderPresenter"
                               Content="{TemplateBinding Header}"
                               Content="{TemplateBinding Header}"
-                              Margin="{TemplateBinding Padding}"
                               VerticalAlignment="Center"
                               VerticalAlignment="Center"
-                              Grid.Column="2">
+                              HorizontalAlignment="Stretch"
+                              TextBlock.Foreground="{TemplateBinding Foreground}"
+                              Grid.Column="1">
               <ContentPresenter.DataTemplates>
               <ContentPresenter.DataTemplates>
                 <DataTemplate DataType="sys:String">
                 <DataTemplate DataType="sys:String">
-                  <AccessText Text="{Binding}"/>
+                  <AccessText Text="{Binding}" />
                 </DataTemplate>
                 </DataTemplate>
               </ContentPresenter.DataTemplates>
               </ContentPresenter.DataTemplates>
             </ContentPresenter>
             </ContentPresenter>
             <TextBlock x:Name="PART_InputGestureText"
             <TextBlock x:Name="PART_InputGestureText"
-                       Grid.Column="3"
-                       Text="{TemplateBinding InputGesture, Converter={StaticResource KeyGestureConverter}}"
-                       VerticalAlignment="Center"/>
-            <Path Name="rightArrow"
-                  Data="M0,0L4,3.5 0,7z"
-                  Fill="{DynamicResource ThemeForegroundBrush}"
-                  Margin="10,0,0,0"
+                       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"
                   VerticalAlignment="Center"
-                  Grid.Column="4"/>
+                  Grid.Column="3" />
             <Popup Name="PART_Popup"
             <Popup Name="PART_Popup"
+                   WindowManagerAddShadowHint="True"
                    PlacementMode="Right"
                    PlacementMode="Right"
                    StaysOpen="True"
                    StaysOpen="True"
-                   IsOpen="{TemplateBinding IsSubMenuOpen, Mode=TwoWay}">
-              <Border Background="{TemplateBinding Background}"
-                      BorderBrush="{DynamicResource ThemeBorderMidBrush}"
-                      BorderThickness="{TemplateBinding BorderThickness}">
-                <ScrollViewer>                  
-                    <ItemsPresenter Name="PART_ItemsPresenter"
-                                    Items="{TemplateBinding Items}"
-                                    ItemsPanel="{TemplateBinding ItemsPanel}"
-                                    ItemTemplate="{TemplateBinding ItemTemplate}"
-                                    Grid.IsSharedSizeScope="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>
                 </ScrollViewer>
               </Border>
               </Border>
             </Popup>
             </Popup>
-            </Grid>
+          </Grid>
         </Border>
         </Border>
       </ControlTemplate>
       </ControlTemplate>
     </Setter>
     </Setter>
   </Style>
   </Style>
 
 
-  <Style Selector="MenuItem:separator">
-    <Setter Property="Template">
-      <ControlTemplate>
-        <Separator Background="{DynamicResource ThemeControlMidBrush}"
-                   Margin="20,1,0,1"
-                   Height="1"/>
-      </ControlTemplate>
-    </Setter>
-  </Style>
-
   <Style Selector="Menu > MenuItem">
   <Style Selector="Menu > MenuItem">
-    <Setter Property="Padding" Value="6 0"/>
     <Setter Property="Template">
     <Setter Property="Template">
       <ControlTemplate>
       <ControlTemplate>
-        <Border Name="root"
+        <Border Name="PART_LayoutRoot"
                 Background="{TemplateBinding Background}"
                 Background="{TemplateBinding Background}"
                 BorderBrush="{TemplateBinding BorderBrush}"
                 BorderBrush="{TemplateBinding BorderBrush}"
                 BorderThickness="{TemplateBinding BorderThickness}">
                 BorderThickness="{TemplateBinding BorderThickness}">
@@ -103,22 +148,31 @@
                               Margin="{TemplateBinding Padding}">
                               Margin="{TemplateBinding Padding}">
               <ContentPresenter.DataTemplates>
               <ContentPresenter.DataTemplates>
                 <DataTemplate DataType="sys:String">
                 <DataTemplate DataType="sys:String">
-                  <AccessText Text="{Binding}"/>
+                  <AccessText Text="{Binding}" />
                 </DataTemplate>
                 </DataTemplate>
               </ContentPresenter.DataTemplates>
               </ContentPresenter.DataTemplates>
             </ContentPresenter>
             </ContentPresenter>
             <Popup Name="PART_Popup"
             <Popup Name="PART_Popup"
-                   IsOpen="{TemplateBinding IsSubMenuOpen, Mode=TwoWay}"
+                   WindowManagerAddShadowHint="False"
+                   MinWidth="{Binding Bounds.Width, RelativeSource={RelativeSource TemplatedParent}}"
+                   IsOpen="{TemplateBinding IsSubMenuOpen,
+                                            Mode=TwoWay}"
                    StaysOpen="True">
                    StaysOpen="True">
-              <Border Background="{TemplateBinding Background}"
-                      BorderBrush="{DynamicResource ThemeBorderMidBrush}"
-                      BorderThickness="{TemplateBinding BorderThickness}">
+              <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>
                 <ScrollViewer>
                   <ItemsPresenter Name="PART_ItemsPresenter"
                   <ItemsPresenter Name="PART_ItemsPresenter"
                                   Items="{TemplateBinding Items}"
                                   Items="{TemplateBinding Items}"
                                   ItemsPanel="{TemplateBinding ItemsPanel}"
                                   ItemsPanel="{TemplateBinding ItemsPanel}"
                                   ItemTemplate="{TemplateBinding ItemTemplate}"
                                   ItemTemplate="{TemplateBinding ItemTemplate}"
-                                  Grid.IsSharedSizeScope="True"/>
+                                  Margin="{DynamicResource MenuFlyoutScrollerMargin}"
+                                  Grid.IsSharedSizeScope="True" />
                 </ScrollViewer>
                 </ScrollViewer>
               </Border>
               </Border>
             </Popup>
             </Popup>
@@ -128,20 +182,78 @@
     </Setter>
     </Setter>
   </Style>
   </Style>
 
 
-  <Style Selector="MenuItem /template/ ItemsPresenter#PART_ItemsPresenter">
-    <Setter Property="Margin" Value="2"/>
+  <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}" />
+  </Style>
+  
+  <Style Selector="MenuItem /template/ ContentPresenter#PART_IconPresenter">
+    <Setter Property="IsVisible" Value="False" />
+  </Style>
+  <Style Selector="MenuItem:icon /template/ ContentPresenter#PART_IconPresenter">
+    <Setter Property="IsVisible" Value="True" />
+  </Style>
+
+  <Style Selector="MenuItem /template/ TextBlock#PART_InputGestureText">
+    <Setter Property="Foreground" Value="{DynamicResource MenuFlyoutItemKeyboardAcceleratorTextForeground}" />
+  </Style>
+  <Style Selector="MenuItem /template/ Path#PART_ChevronPath">
+    <Setter Property="Fill" Value="{DynamicResource MenuFlyoutSubItemChevron}" />
   </Style>
   </Style>
 
 
-  <Style Selector="MenuItem:selected /template/ Border#root">
-    <Setter Property="Background" Value="{DynamicResource ThemeAccentBrush4}"/>
-    <Setter Property="BorderBrush" Value="{DynamicResource ThemeAccentBrush}"/>
+  <Style Selector="MenuItem:selected /template/ Border#PART_LayoutRoot">
+    <Setter Property="Background" Value="{DynamicResource MenuFlyoutItemBackgroundPointerOver}" />
+    <Setter Property="BorderBrush" Value="{DynamicResource MenuFlyoutItemBorderBrushPointerOver}" />
+  </Style>
+  <Style Selector="MenuItem:selected /template/ TextBlock#PART_InputGestureText">
+    <Setter Property="Foreground" Value="{DynamicResource MenuFlyoutItemKeyboardAcceleratorTextForegroundPointerOver}" />
+  </Style>
+  <Style Selector="MenuItem:selected /template/ Path#PART_ChevronPath">
+    <Setter Property="Fill" Value="{DynamicResource MenuFlyoutSubItemChevronPointerOver}" />
   </Style>
   </Style>
 
 
-  <Style Selector="MenuItem:empty /template/ Path#rightArrow">
-    <Setter Property="IsVisible" Value="False"/>
+  <Style Selector="MenuItem:pressed /template/ Border#PART_LayoutRoot">
+    <Setter Property="Background" Value="{DynamicResource MenuFlyoutItemBackgroundPressed}" />
+    <Setter Property="BorderBrush" Value="{DynamicResource MenuFlyoutItemBorderBrushPressed}" />
+  </Style>
+  <Style Selector="MenuItem:pressed /template/ TextBlock#PART_InputGestureText">
+    <Setter Property="Foreground" Value="{DynamicResource MenuFlyoutItemKeyboardAcceleratorTextForegroundPressed}" />
+  </Style>
+  <Style Selector="MenuItem:pressed /template/ Path#PART_ChevronPath">
+    <Setter Property="Fill" Value="{DynamicResource MenuFlyoutSubItemChevronPressed}" />
   </Style>
   </Style>
 
 
   <Style Selector="MenuItem:disabled">
   <Style Selector="MenuItem:disabled">
-    <Setter Property="Opacity" Value="{DynamicResource ThemeDisabledOpacity}"/>
+    <Setter Property="Background" Value="{DynamicResource MenuFlyoutItemBackgroundDisabled}" />
+    <Setter Property="BorderBrush" Value="{DynamicResource MenuFlyoutItemBorderBrushDisabled}" />
+  </Style>
+  <Style Selector="MenuItem:disabled /template/ TextBlock#PART_InputGestureText">
+    <Setter Property="Foreground" Value="{DynamicResource MenuFlyoutItemKeyboardAcceleratorTextForegroundDisabled}" />
+  </Style>
+  <Style Selector="MenuItem:disabled /template/ Path#PART_ChevronPath">
+    <Setter Property="Fill" Value="{DynamicResource MenuFlyoutSubItemChevronDisabled}" />
+  </Style>
+
+  <Style Selector="MenuItem:open /template/ Path#PART_ChevronPath">
+    <Setter Property="Fill" Value="{DynamicResource MenuFlyoutSubItemChevronSubMenuOpened}" />
+  </Style>
+
+  <Style Selector="MenuItem:empty /template/ Path#PART_ChevronPath">
+    <Setter Property="IsVisible" Value="False" />
+  </Style>
+
+  <Style Selector="MenuItem:separator">
+    <Setter Property="Template">
+      <ControlTemplate>
+        <Separator />
+      </ControlTemplate>
+    </Setter>
+  </Style>
+
+  <Style Selector="MenuItem > Separator, ContextMenu > Separator">
+    <Setter Property="Background" Value="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" />
+    <Setter Property="HorizontalAlignment" Value="Stretch" />
+    <Setter Property="Margin" Value="{DynamicResource MenuFlyoutSeparatorThemePadding}" />
+    <Setter Property="Height" Value="{DynamicResource MenuFlyoutSeparatorThemeHeight}" />
   </Style>
   </Style>
 </Styles>
 </Styles>

+ 5 - 7
src/Avalonia.Themes.Fluent/Separator.xaml

@@ -4,17 +4,15 @@
     <Setter Property="Focusable" Value="False"/>
     <Setter Property="Focusable" Value="False"/>
     <Setter Property="Template">
     <Setter Property="Template">
       <ControlTemplate>
       <ControlTemplate>
-        <Border BorderBrush="{TemplateBinding BorderBrush}"
+        <Border Padding="{TemplateBinding Margin}"
+                Height="{TemplateBinding Height}"
+                HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
+                VerticalAlignment="{TemplateBinding VerticalAlignment}"
+                BorderBrush="{TemplateBinding BorderBrush}"
                 BorderThickness="{TemplateBinding BorderThickness}"
                 BorderThickness="{TemplateBinding BorderThickness}"
                 Background="{TemplateBinding Background}"/>
                 Background="{TemplateBinding Background}"/>
       </ControlTemplate>
       </ControlTemplate>
     </Setter>
     </Setter>
   </Style>
   </Style>
 
 
-  <Style Selector="MenuItem > Separator, ContextMenu > Separator">
-    <Setter Property="Background" Value="{DynamicResource ThemeControlMidBrush}"/>
-    <Setter Property="Margin" Value="29,1,0,1"/>
-    <Setter Property="Height" Value="1"/>
-  </Style>
-
 </Styles>
 </Styles>

+ 294 - 0
src/Avalonia.Themes.Fluent/ToggleSwitch.xaml

@@ -0,0 +1,294 @@
+<Styles xmlns="https://github.com/avaloniaui"
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+        xmlns:sys="clr-namespace:System;assembly=netstandard">
+  <Styles.Resources>
+    <Thickness x:Key="ToggleSwitchTopHeaderMargin">0,0,0,6</Thickness>
+    <x:Double x:Key="ToggleSwitchPreContentMargin">6</x:Double>
+    <x:Double x:Key="ToggleSwitchPostContentMargin">6</x:Double>
+    <x:Double x:Key="ToggleSwitchThemeMinWidth">154</x:Double>
+    <x:Double x:Key="KnobOnPosition">20</x:Double>
+    <x:Double x:Key="KnobOffPosition">0</x:Double>
+  </Styles.Resources>
+  <Design.PreviewWith>
+    <StackPanel Margin="20" Width="250" Spacing="24" >
+      <StackPanel Spacing="12" >
+        <TextBlock
+          Text="Automatic updates"
+          Classes="h1"/>
+        <TextBlock
+          Text="Updates will be automaticly Downloaded and installed shile the computer is shutting down or restarting"
+          TextWrapping="Wrap"/>
+        <ToggleSwitch HorizontalContentAlignment="Left"
+          Content="Enable automatic Updates?"
+          OffContent="Uit"
+          OnContent="Aan"
+          VerticalAlignment="Bottom"/>
+      </StackPanel>
+
+      <StackPanel Spacing="12">
+        <TextBlock
+          Text="Previewer"
+          Classes="h1"/>
+        <TextBlock
+          Text="The previewer Shows a preview off your code, this could slow down your system"
+          TextWrapping="Wrap"/>
+        <ToggleSwitch
+          Content="Previewer"
+          IsChecked="True" />
+      </StackPanel>
+    </StackPanel>
+  </Design.PreviewWith>
+
+  <Style Selector="ToggleSwitch">
+    <Setter Property="Foreground" Value="{DynamicResource ToggleSwitchContentForeground}" />
+    <Setter Property="HorizontalAlignment" Value="Left" />
+    <Setter Property="VerticalAlignment" Value="Center" />
+    <Setter Property="HorizontalContentAlignment" Value="Left" />
+    <Setter Property="FontFamily" Value="{DynamicResource ContentControlThemeFontFamily}" />
+    <Setter Property="FontSize" Value="{DynamicResource ControlContentThemeFontSize}" />
+    <Setter Property="Template">
+      <ControlTemplate>
+        <Grid Background="{TemplateBinding Background}"
+          RowDefinitions="Auto,*">
+
+          <ContentPresenter x:Name="PART_ContentPresenter"
+            Grid.Row="0"
+            Content="{TemplateBinding Content}"
+            ContentTemplate="{TemplateBinding ContentTemplate}"
+            Margin="{DynamicResource ToggleSwitchTopHeaderMargin}"
+            VerticalAlignment="Top"/>
+
+          <Grid Grid.Row="1"
+            MinWidth="{StaticResource ToggleSwitchThemeMinWidth}"
+            HorizontalAlignment="Left"
+            VerticalAlignment="Top">
+
+            <Grid.RowDefinitions>
+              <RowDefinition Height="{DynamicResource ToggleSwitchPreContentMargin}" />
+              <RowDefinition Height="Auto" />
+              <RowDefinition Height="{DynamicResource ToggleSwitchPostContentMargin}" />
+            </Grid.RowDefinitions>
+
+            <Grid.ColumnDefinitions>
+              <ColumnDefinition Width="Auto" />
+              <ColumnDefinition Width="12" MaxWidth="12" />
+              <ColumnDefinition Width="Auto" />
+            </Grid.ColumnDefinitions>
+
+            <Grid x:Name="SwitchAreaGrid"
+              Grid.RowSpan="3"
+              Grid.ColumnSpan="3"
+              TemplatedControl.IsTemplateFocusTarget="True"
+              Margin="0,5" />
+
+            <ContentPresenter x:Name="PART_OffContentPresenter"
+              Grid.RowSpan="3"
+              Grid.Column="2"
+              Content="{TemplateBinding OffContent}"
+              ContentTemplate="{TemplateBinding OffContentTemplate}"
+              HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
+              VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
+
+            <ContentPresenter x:Name="PART_OnContentPresenter"
+              Grid.RowSpan="3"
+              Grid.Column="2"
+              Content="{TemplateBinding OnContent}"
+              ContentTemplate="{TemplateBinding OnContentTemplate}"
+              HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
+              VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
+
+            <Border x:Name="OuterBorder"
+              Grid.Row="1"
+              Height="20"
+              Width="40"
+              CornerRadius="10"
+              BorderThickness="{DynamicResource ToggleSwitchOuterBorderStrokeThickness}" />
+
+            <Border x:Name="SwitchKnobBounds"
+              Grid.Row="1"
+              Height="20"
+              Width="40"
+              CornerRadius="10"
+              BorderThickness="{DynamicResource ToggleSwitchOnStrokeThickness}"/>
+
+            <Canvas x:Name="SwitchKnob" Grid.Row="1"
+               HorizontalAlignment="Left"
+               Width="20" Height="20">
+
+              <Grid x:Name="MovingKnobs"
+                Width="20" Height="20">
+
+                <Ellipse x:Name="SwitchKnobOn"
+                         Width="10" Height="10" />
+
+                <Ellipse x:Name="SwitchKnobOff"
+                         Width="10" Height="10" />
+              </Grid>
+            </Canvas>
+          </Grid>
+        </Grid>
+      </ControlTemplate>
+    </Setter>
+  </Style>
+
+  <!-- NormalState -->
+  <Style Selector="ToggleSwitch /template/ Grid#SwitchAreaGrid">
+    <Setter Property="Background" Value="{DynamicResource ToggleSwitchContainerBackground}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch /template/ Border#OuterBorder">
+    <Setter Property="Background" Value="{DynamicResource ToggleSwitchFillOff}"/>
+    <Setter Property="BorderBrush" Value="{DynamicResource ToggleSwitchStrokeOff}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch /template/ Border#SwitchKnobBounds">
+    <Setter Property="Background" Value="{DynamicResource ToggleSwitchFillOn}"/>
+    <Setter Property="BorderBrush" Value="{DynamicResource ToggleSwitchStrokeOn}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch /template/ Ellipse#SwitchKnobOn">
+    <Setter Property="Fill" Value="{DynamicResource ToggleSwitchKnobFillOn}"/>
+    <Setter Property="Stroke" Value="{DynamicResource ToggleSwitchKnobStrokeOn}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch /template/ Ellipse#SwitchKnobOff">
+    <Setter Property="Fill" Value="{DynamicResource ToggleSwitchKnobFillOff}"/>
+    <Setter Property="Stroke" Value="{DynamicResource ToggleSwitchKnobStrokeOff}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch /template/ Grid#MovingKnobs">
+    <Setter Property="Canvas.Left" Value="{DynamicResource KnobOffPosition}"/>
+    <Setter Property="Transitions">
+      <Transitions>
+        <DoubleTransition Property="Canvas.Left" Duration="0:0:0.2" Easing="CubicEaseOut"/>
+      </Transitions>
+    </Setter>
+  </Style>
+
+  <!-- PointerOverState -->
+  <Style Selector="ToggleSwitch:pointerover /template/ Border#OuterBorder">
+    <Setter Property="BorderBrush" Value="{DynamicResource ToggleSwitchStrokeOffPointerOver}"/>
+    <Setter Property="Background" Value="{DynamicResource ToggleSwitchFillOffPointerOver}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:pointerover /template/ Ellipse#SwitchKnobOff">
+    <Setter Property="Fill" Value="{DynamicResource ToggleSwitchKnobFillOffPointerOver}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:pointerover /template/ Ellipse#SwitchKnobOn">
+    <Setter Property="Fill" Value="{DynamicResource ToggleSwitchKnobFillOnPointerOver}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:pointerover /template/ Border#SwitchKnobBounds">
+    <Setter Property="Background" Value="{DynamicResource ToggleSwitchFillOnPointerOver}"/>
+    <Setter Property="BorderBrush" Value="{DynamicResource ToggleSwitchStrokeOnPointerOver}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:pointerover /template/ Grid#SwitchAreaGrid">
+    <Setter Property="Background" Value="{DynamicResource ToggleSwitchContainerBackgroundPointerOver}"/>
+  </Style>
+
+  <!-- PressedState -->
+  <Style Selector="ToggleSwitch:pressed /template/ Border#OuterBorder">
+    <Setter Property="BorderBrush" Value="{DynamicResource ToggleSwitchStrokeOffPressed}"/>
+    <Setter Property="Background" Value="{DynamicResource ToggleSwitchFillOffPressed}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:pressed /template/ Border#SwitchKnobBounds">
+    <Setter Property="Background" Value="{DynamicResource ToggleSwitchFillOnPressed}"/>
+    <Setter Property="BorderBrush" Value="{DynamicResource ToggleSwitchStrokeOnPressed}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:pressed /template/ Ellipse#SwitchKnobOff">
+    <Setter Property="Fill" Value="{DynamicResource ToggleSwitchKnobFillOffPressed}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:pressed /template/ Ellipse#SwitchKnobOn">
+    <Setter Property="Fill" Value="{DynamicResource ToggleSwitchKnobFillOnPressed}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:pressed /template/ Grid#SwitchAreaGrid">
+    <Setter Property="Background" Value="{DynamicResource ToggleSwitchContainerBackgroundPressed}"/>
+  </Style>
+
+  <!-- DisabledState -->
+  <Style Selector="ToggleSwitch:disabled">
+    <Setter Property="Foreground" Value="{DynamicResource ToggleSwitchHeaderForegroundDisabled}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:disabled /template/ Border#OuterBorder">
+    <Setter Property="BorderBrush" Value="{DynamicResource ToggleSwitchStrokeOffDisabled}"/>
+    <Setter Property="Background" Value="{DynamicResource ToggleSwitchFillOffPressed}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:disabled /template/ Ellipse#SwitchKnobOff">
+    <Setter Property="Fill" Value="{DynamicResource ToggleSwitchKnobFillOffDisabled}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:disabled /template/ Ellipse#SwitchKnobOn">
+    <Setter Property="Fill" Value="{DynamicResource ToggleSwitchKnobFillOnDisabled}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:disabled /template/ Border#SwitchKnobBounds">
+    <Setter Property="Background" Value="{DynamicResource ToggleSwitchFillOnDisabled}"/>
+    <Setter Property="BorderBrush" Value="{DynamicResource ToggleSwitchStrokeOnDisabled}"/>
+  </Style>
+
+  <!-- CheckedState -->
+  <Style Selector="ToggleSwitch:checked /template/ Grid#MovingKnobs">
+    <Setter Property="Canvas.Left" Value="{DynamicResource KnobOnPosition}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:checked /template/ Border#OuterBorder">
+    <Setter Property="Opacity" Value="0"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:checked  /template/ Ellipse#SwitchKnobOff">
+    <Setter Property="Opacity" Value="0"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:checked  /template/ Border#SwitchKnobBounds">
+    <Setter Property="Opacity" Value="1"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:checked /template/ Ellipse#SwitchKnobOn">
+    <Setter Property="Opacity" Value="1"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:checked /template/ ContentPresenter#PART_OffContentPresenter">
+    <Setter Property="Opacity" Value="0"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:checked /template/ ContentPresenter#PART_OnContentPresenter">
+    <Setter Property="Opacity" Value="1"/>
+  </Style>
+
+  <!--UncheckedState -->
+  <Style Selector="ToggleSwitch:unchecked /template/ Grid#MovingKnobs">
+    <Setter Property="Canvas.Left" Value="{DynamicResource KnobOffPosition}"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:unchecked /template/ Border#OuterBorder">
+    <Setter Property="Opacity" Value="1"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:unchecked /template/ Ellipse#SwitchKnobOff">
+    <Setter Property="Opacity" Value="1"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:unchecked /template/ Ellipse#SwitchKnobOn">
+    <Setter Property="Opacity" Value="0"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:unchecked  /template/ Border#SwitchKnobBounds">
+    <Setter Property="Opacity" Value="0"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:unchecked /template/ ContentPresenter#PART_OffContentPresenter">
+    <Setter Property="Opacity" Value="1"/>
+  </Style>
+
+  <Style Selector="ToggleSwitch:unchecked /template/ ContentPresenter#PART_OnContentPresenter">
+    <Setter Property="Opacity" Value="0"/>
+  </Style>
+</Styles>

+ 17 - 1
src/Avalonia.X11/XI2Manager.cs

@@ -97,7 +97,7 @@ namespace Avalonia.X11
         {
         {
             _platform = platform;
             _platform = platform;
             _x11 = platform.Info;
             _x11 = platform.Info;
-            _multitouch = platform.Options?.EnableMultiTouch ?? false;
+            _multitouch = platform.Options?.EnableMultiTouch ?? true;
             var devices =(XIDeviceInfo*) XIQueryDevice(_x11.Display,
             var devices =(XIDeviceInfo*) XIQueryDevice(_x11.Display,
                 (int)XiPredefinedDeviceId.XIAllMasterDevices, out int num);
                 (int)XiPredefinedDeviceId.XIAllMasterDevices, out int num);
             for (var c = 0; c < num; c++)
             for (var c = 0; c < num; c++)
@@ -237,6 +237,22 @@ namespace Avalonia.X11
                         RawPointerEventType.Move, ev.Position, ev.Modifiers));
                         RawPointerEventType.Move, ev.Position, ev.Modifiers));
             }
             }
 
 
+            if (ev.Type == XiEventType.XI_ButtonPress && ev.Button >= 4 && ev.Button <= 7 && !ev.Emulated)
+            {
+                Vector? scrollDelta = ev.Button switch
+                {
+                    4 => new Vector(0, 1),
+                    5 => new Vector(0, -1),
+                    6 => new Vector(1, 0),
+                    7 => new Vector(-1, 0),
+                    _ => null
+                };
+
+                if (scrollDelta.HasValue)
+                    client.ScheduleXI2Input(new RawMouseWheelEventArgs(client.MouseDevice, ev.Timestamp,
+                        client.InputRoot, ev.Position, scrollDelta.Value, ev.Modifiers));
+            }
+
             if (ev.Type == XiEventType.XI_ButtonPress || ev.Type == XiEventType.XI_ButtonRelease)
             if (ev.Type == XiEventType.XI_ButtonPress || ev.Type == XiEventType.XI_ButtonRelease)
             {
             {
                 var down = ev.Type == XiEventType.XI_ButtonPress;
                 var down = ev.Type == XiEventType.XI_ButtonPress;

+ 1 - 1
src/Windows/Avalonia.Win32/WindowImpl.cs

@@ -577,7 +577,7 @@ namespace Avalonia.Win32
 
 
             Handle = new PlatformHandle(_hwnd, PlatformConstants.WindowHandleType);
             Handle = new PlatformHandle(_hwnd, PlatformConstants.WindowHandleType);
 
 
-            _multitouch = Win32Platform.Options.EnableMultitouch ?? false;
+            _multitouch = Win32Platform.Options.EnableMultitouch ?? true;
 
 
             if (_multitouch)
             if (_multitouch)
             {
             {