Преглед изворни кода

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).
 
@@ -30,6 +26,15 @@ Install-Package Avalonia
 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
 
 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">
                 <TextBlock>Hover Here</TextBlock>
             </Border>
-            <CheckBox Grid.Column="1"
+            <ToggleSwitch Grid.Column="1"
                       Margin="5"
                       Grid.Row="0"
                       IsChecked="{Binding ElementName=Border, Path=(ToolTip.IsOpen)}"

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

@@ -1,17 +1,18 @@
 using System;
 using System.Collections.Generic;
 using System.ComponentModel;
-using System.Linq;
 using Avalonia.Controls.Generators;
 using Avalonia.Controls.Platform;
 using Avalonia.Controls.Primitives;
+using Avalonia.Controls.Primitives.PopupPositioning;
 using Avalonia.Controls.Templates;
 using Avalonia.Input;
 using Avalonia.Interactivity;
 using Avalonia.Layout;
-using Avalonia.LogicalTree;
 using Avalonia.Styling;
 
+#nullable enable
+
 namespace Avalonia.Controls
 {
     /// <summary>
@@ -19,11 +20,59 @@ namespace Avalonia.Controls
     /// </summary>
     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 =
             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>
         /// Initializes a new instance of the <see cref="ContextMenu"/> class.
@@ -47,23 +96,107 @@ namespace Avalonia.Controls
         /// </summary>
         static ContextMenu()
         {
-            ItemsPanelProperty.OverrideDefaultValue(typeof(ContextMenu), DefaultPanel);
+            ItemsPanelProperty.OverrideDefaultValue<ContextMenu>(DefaultPanel);
+            PlacementModeProperty.OverrideDefaultValue<ContextMenu>(PlacementMode.Pointer);
             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>
         /// Occurs when the value of the
         /// <see cref="P:Avalonia.Controls.ContextMenu.IsOpen" />
         /// property is changing from false to true.
         /// </summary>
-        public event CancelEventHandler ContextMenuOpening;
+        public event CancelEventHandler? ContextMenuOpening;
 
         /// <summary>
         /// Occurs when the value of the
         /// <see cref="P:Avalonia.Controls.ContextMenu.IsOpen" />
         /// property is changing from true to false.
         /// </summary>
-        public event CancelEventHandler ContextMenuClosing;
+        public event CancelEventHandler? ContextMenuClosing;
 
         /// <summary>
         /// Called when the <see cref="Control.ContextMenu"/> property changes on a control.
@@ -77,7 +210,7 @@ namespace Avalonia.Controls
             {
                 control.PointerReleased -= ControlPointerReleased;
                 oldMenu._attachedControls?.Remove(control);
-                ((ISetLogicalParent)oldMenu._popup)?.SetParent(null);
+                ((ISetLogicalParent?)oldMenu._popup)?.SetParent(null);
             }
 
             if (e.NewValue is ContextMenu newMenu)
@@ -97,7 +230,7 @@ namespace Avalonia.Controls
         /// Opens a context menu on the specified control.
         /// </summary>
         /// <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))
             {
@@ -113,7 +246,7 @@ namespace Avalonia.Controls
                     nameof(control));
             }
 
-            control ??= _attachedControls[0];
+            control ??= _attachedControls![0];
 
             if (IsOpen)
             {
@@ -124,8 +257,14 @@ namespace Avalonia.Controls
             {
                 _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
                 };
 
@@ -204,7 +343,7 @@ namespace Avalonia.Controls
 
             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.

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

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

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

@@ -5,19 +5,70 @@ using Avalonia.VisualTree;
 
 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
     {
+        /// <summary>
+        /// Sets the control to display in the popup.
+        /// </summary>
+        /// <param name="control"></param>
         void SetChild(IControl control);
+
+        /// <summary>
+        /// Gets the presenter from the control's template.
+        /// </summary>
         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; }
 
+        /// <summary>
+        /// Raised when the control's template is applied.
+        /// </summary>
         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,
-            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();
+
+        /// <summary>
+        /// Hides the popup.
+        /// </summary>
         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,
             StyledProperty<double> minWidthProperty, StyledProperty<double> maxWidthProperty,
             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,
-            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,
-                gravity);
+                gravity, constraintAdjustment, rect);
             UpdatePosition();
         }
 
@@ -122,10 +124,8 @@ namespace Avalonia.Controls.Primitives
             }, 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)
         {
             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.Reactive.Disposables;
 using Avalonia.Controls.Presenters;
+using Avalonia.Controls.Primitives.PopupPositioning;
 using Avalonia.Input;
 using Avalonia.Input.Raw;
 using Avalonia.Interactivity;
@@ -37,12 +38,45 @@ namespace Avalonia.Controls.Primitives
                 o => o.IsOpen,
                 (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>
         /// Defines the <see cref="PlacementMode"/> property.
         /// </summary>
         public static readonly StyledProperty<PlacementMode> PlacementModeProperty =
             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
         /// <summary>
         /// Defines the <see cref="ObeyScreenEdges"/> property.
@@ -63,12 +97,6 @@ namespace Avalonia.Controls.Primitives
         public static readonly StyledProperty<double> VerticalOffsetProperty =
             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>
         /// Defines the <see cref="StaysOpen"/> property.
         /// </summary>
@@ -145,6 +173,36 @@ namespace Avalonia.Controls.Primitives
             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>
         /// Gets or sets the placement mode of the popup in relation to the <see cref="PlacementTarget"/>.
         /// </summary>
@@ -154,6 +212,32 @@ namespace Avalonia.Controls.Primitives
             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")]
         public bool ObeyScreenEdges
         {
@@ -162,7 +246,7 @@ namespace Avalonia.Controls.Primitives
         }
 
         /// <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>
         public double HorizontalOffset
         {
@@ -171,7 +255,7 @@ namespace Avalonia.Controls.Primitives
         }
 
         /// <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>
         public double VerticalOffset
         {
@@ -179,15 +263,6 @@ namespace Avalonia.Controls.Primitives
             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>
         /// Gets or sets a value indicating whether the popup should stay open when the popup is
         /// pressed or loses focus.
@@ -260,8 +335,12 @@ namespace Avalonia.Controls.Primitives
 
             popupHost.ConfigurePosition(
                 placementTarget,
-                PlacementMode, 
-                new Point(HorizontalOffset, VerticalOffset));
+                PlacementMode,
+                new Point(HorizontalOffset, VerticalOffset),
+                PlacementAnchor,
+                PlacementGravity,
+                PlacementConstraintAdjustment,
+                PlacementRect);
 
             DeferCleanup(SubscribeToEventHandler<IPopupHost, EventHandler<TemplateAppliedEventArgs>>(popupHost, RootTemplateApplied,
                 (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
 {
     /// <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>
+    /// <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
     {
-        private PopupPositioningEdge _gravity;
-        private PopupPositioningEdge _anchor;
+        private PopupGravity _gravity;
+        private PopupAnchor _anchor;
 
         /// <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>
         public Size Size { get; set; }
 
         /// <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>
+        /// <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; }
 
-
         /// <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>
-        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;
             set
@@ -100,66 +102,70 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
         }
 
         /// <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>
-        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;
             set
             {
-                PopupPositioningEdgeHelper.ValidateEdge(value);
+                PopupPositioningEdgeHelper.ValidateGravity(value);
                 _gravity = value;
             }
         }
 
         /// <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.
-        /// </summary>
+        /// </remarks>
         public PopupPositionerConstraintAdjustment ConstraintAdjustment { get; set; }
-        
+
         /// <summary>
         /// 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>
+        /// <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; }
     }
-    
+
     /// <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>
+    /// <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]
     public enum PopupPositionerConstraintAdjustment
     {
@@ -171,79 +177,97 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
 
         /// <summary>
         /// 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>
+        /// <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,
 
-
         /// <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>
+        /// <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,
 
         /// <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>
+        /// <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,
 
         /// <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,
-        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
     {
-        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");
         }
 
-        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)
                 edge ^= hmask;
             if ((edge & vmask) != 0)
@@ -251,43 +275,167 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
             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;
         }
         
-        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;
         }
-        
+
+        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]
-    public enum PopupPositioningEdge
+    public enum PopupAnchor
     {
+        /// <summary>
+        /// The center of the anchor rectangle.
+        /// </summary>
         None,
+
+        /// <summary>
+        /// The top edge of the anchor rectangle.
+        /// </summary>
         Top = 1,
+
+        /// <summary>
+        /// The bottom edge of the anchor rectangle.
+        /// </summary>
         Bottom = 2,
+
+        /// <summary>
+        /// The left edge of the anchor rectangle.
+        /// </summary>
         Left = 4,
+
+        /// <summary>
+        /// The right edge of the anchor rectangle.
+        /// </summary>
         Right = 8,
+
+        /// <summary>
+        /// The top-left corner of the anchor rectangle.
+        /// </summary>
         TopLeft = Top | Left,
+
+        /// <summary>
+        /// The top-right corner of the anchor rectangle.
+        /// </summary>
         TopRight = Top | Right,
+
+        /// <summary>
+        /// The bottom-left corner of the anchor rectangle.
+        /// </summary>
         BottomLeft = Bottom | Left,
+
+        /// <summary>
+        /// The bottom-right corner of the anchor rectangle.
+        /// </summary>
         BottomRight = Bottom | Right,
 
-        
+        /// <summary>
+        /// A mask for the vertical component flags.
+        /// </summary>
         VerticalMask = Top | Bottom,
+
+        /// <summary>
+        /// A mask for the horizontal component flags.
+        /// </summary>
         HorizontalMask = Left | Right,
+
+        /// <summary>
+        /// A mask for all flags.
+        /// </summary>
         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
     {
+        /// <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);
     }
 
@@ -296,18 +444,19 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
         public static void ConfigurePosition(ref this PopupPositionerParameters positionerParameters,
             TopLevel topLevel,
             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
             var pointer = topLevel.PointToClient(topLevel.PlatformImpl.MouseDevice.Position);
             
             positionerParameters.Offset = offset;
-            positionerParameters.ConstraintAdjustment = PopupPositionerConstraintAdjustment.All;
+            positionerParameters.ConstraintAdjustment = constraintAdjustment;
             if (placement == PlacementMode.Pointer)
             {
                 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
             {
@@ -317,32 +466,33 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
                 if (matrix == 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)
                 {
-                    positionerParameters.Anchor = PopupPositioningEdge.TopRight;
-                    positionerParameters.Gravity = PopupPositioningEdge.BottomRight;
+                    positionerParameters.Anchor = PopupAnchor.TopRight;
+                    positionerParameters.Gravity = PopupGravity.BottomRight;
                 }
                 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)
                 {
-                    positionerParameters.Anchor = PopupPositioningEdge.TopLeft;
-                    positionerParameters.Gravity = PopupPositioningEdge.BottomLeft;
+                    positionerParameters.Anchor = PopupAnchor.TopLeft;
+                    positionerParameters.Gravity = PopupGravity.BottomLeft;
                 }
                 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)
                 {

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

@@ -1,6 +1,7 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using System.Transactions;
 
 namespace Avalonia.Controls.Primitives.PopupPositioning
 {
@@ -8,9 +9,8 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
     {
         IReadOnlyList<ManagedPopupPositionerScreenInfo> Screens { get; }
         Rect ParentClientAreaScreenGeometry { get; }
+        double Scaling { get; }
         void MoveAndResize(Point devicePoint, Size virtualSize);
-        Point TranslatePoint(Point pt);
-        Size TranslateSize(Size size);
     }
 
     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
     {
         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;
-            if ((edge & PopupPositioningEdge.Left) != 0)
+            if ((edge & PopupAnchor.Left) != 0)
                 x = anchorRect.X;
-            else if ((edge & PopupPositioningEdge.Right) != 0)
+            else if ((edge & PopupAnchor.Right) != 0)
                 x = anchorRect.Right;
             else
                 x = anchorRect.X + anchorRect.Width / 2;
             
-            if ((edge & PopupPositioningEdge.Top) != 0)
+            if ((edge & PopupAnchor.Top) != 0)
                 y = anchorRect.Y;
-            else if ((edge & PopupPositioningEdge.Bottom) != 0)
+            else if ((edge & PopupAnchor.Bottom) != 0)
                 y = anchorRect.Bottom;
             else
                 y = anchorRect.Y + anchorRect.Height / 2;
             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;
-            if ((gravity & PopupPositioningEdge.Left) != 0)
+            if ((gravity & PopupGravity.Left) != 0)
                 x = -size.Width;
-            else if ((gravity & PopupPositioningEdge.Right) != 0)
+            else if ((gravity & PopupGravity.Right) != 0)
                 x = 0;
             else
                 x = -size.Width / 2;
             
-            if ((gravity & PopupPositioningEdge.Top) != 0)
+            if ((gravity & PopupGravity.Top) != 0)
                 y = -size.Height;
-            else if ((gravity & PopupPositioningEdge.Bottom) != 0)
+            else if ((gravity & PopupGravity.Bottom) != 0)
                 y = 0;
             else
                 y = -size.Height / 2;
@@ -75,17 +79,24 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
 
         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)
         {
             var parentGeometry = _popup.ParentClientAreaScreenGeometry;
@@ -112,28 +123,30 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
 
             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)
                     return false;
 
-                if ((edge & PopupPositioningEdge.Top) != 0
+                if ((edge & PopupAnchor.Top) != 0
                     && rc.Y < bounds.Y)
                     return false;
 
-                if ((edge & PopupPositioningEdge.Right) != 0
+                if ((edge & PopupAnchor.Right) != 0
                     && rc.Right > bounds.Right)
                     return false;
 
-                if ((edge & PopupPositioningEdge.Bottom) != 0
+                if ((edge & PopupAnchor.Bottom) != 0
                     && rc.Bottom > bounds.Bottom)
                     return false;
 
                 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);
 
 
@@ -141,11 +154,11 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
 
             // If flipping geometry and anchor is allowed and helps, use the flipped one,
             // otherwise leave it as is
-            if (!FitsInBounds(geo, PopupPositioningEdge.HorizontalMask)
+            if (!FitsInBounds(geo, PopupAnchor.HorizontalMask)
                 && (constraintAdjustment & PopupPositionerConstraintAdjustment.FlipX) != 0)
             {
                 var flipped = GetUnconstrained(anchor.FlipX(), gravity.FlipX());
-                if (FitsInBounds(flipped, PopupPositioningEdge.HorizontalMask))
+                if (FitsInBounds(flipped, PopupAnchor.HorizontalMask))
                     geo = geo.WithX(flipped.X);
             }
 
@@ -157,13 +170,34 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
                     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,
             // otherwise leave it as is
-            if (!FitsInBounds(geo, PopupPositioningEdge.VerticalMask)
+            if (!FitsInBounds(geo, PopupAnchor.VerticalMask)
                 && (constraintAdjustment & PopupPositionerConstraintAdjustment.FlipY) != 0)
             {
                 var flipped = GetUnconstrained(anchor.FlipY(), gravity.FlipY());
-                if (FitsInBounds(flipped, PopupPositioningEdge.VerticalMask))
+                if (FitsInBounds(flipped, PopupAnchor.VerticalMask))
                     geo = geo.WithY(flipped.Y);
             }
 
@@ -175,7 +209,28 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
                     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
                 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);
 
             }
@@ -43,8 +43,6 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
             _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,
-            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,
-                placement, offset, anchor, gravity);
+                placement, offset, anchor, gravity, constraintAdjustment, rect);
 
             if (_positionerParameters.Size != default)
                 UpdatePosition();

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

@@ -259,7 +259,7 @@ namespace Avalonia.Controls.Primitives
                 CoerceLength(ref increaseButtonLength, 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);
 
                 if (DecreaseButton != null)

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

@@ -201,7 +201,7 @@ namespace Avalonia.Controls
             var invert = orient ? 0 : 1;
             var calcVal = Math.Abs(invert - logicalPos);
             var range = Maximum - Minimum;
-            var finalValue = calcVal * range;
+            var finalValue = calcVal * range + Minimum;
 
             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.NotificationCard.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>

+ 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="SystemControlErrorTextForegroundBrush" Color="{StaticResource SystemErrorTextColor}" />
     <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 -->
     <!--<AcrylicBrush x:Key="SystemControlTransientBackgroundBrush" BackgroundSource="HostBackdrop" TintColor="{StaticResource SystemChromeAltHighColor}" TintOpacity="0.8" FallbackColor="{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="SystemControlErrorTextForegroundBrush" Color="{StaticResource SystemErrorTextColor}" />
     <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 -->
     <!--<AcrylicBrush x:Key="SystemControlTransientBackgroundBrush" BackgroundSource="HostBackdrop" TintColor="{StaticResource SystemChromeAltHighColor}" TintOpacity="0.8" FallbackColor="{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">
   <Style.Resources>
     <!-- Resources for Button.xaml -->
@@ -62,7 +62,7 @@
     <SolidColorBrush x:Key="RepeatButtonPointerOverForegroundThemeBrush" Color="#FFFFFFFF" />
     <SolidColorBrush x:Key="RepeatButtonPressedBackgroundThemeBrush" Color="#FFFFFFFF" />
     <SolidColorBrush x:Key="RepeatButtonPressedForegroundThemeBrush" Color="#FF000000" />
-    
+
     <!-- Resources for ToggleButton.xaml -->
     <Thickness x:Key="ToggleButtonBorderThemeThickness">1</Thickness>
     <StaticResource x:Key="ToggleButtonBackground" ResourceKey="SystemControlBackgroundBaseLowBrush" />
@@ -182,8 +182,8 @@
     <StaticResource x:Key="ComboBoxDropDownGlyphForeground" ResourceKey="SystemControlForegroundBaseMediumHighBrush" />
     <StaticResource x:Key="ComboBoxDropDownGlyphForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
     <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="ComboBoxDropDownBorderBrush" ResourceKey="SystemControlTransientBorderBrush" />
 
@@ -250,6 +250,92 @@
     <SolidColorBrush x:Key="ListBoxItemSelectedForegroundThemeBrush" Color="White" />
     <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 -->
     <SolidColorBrush x:Key="TextBoxForegroundHeaderThemeBrush" Color="#FFFFFFFF" />
     <SolidColorBrush x:Key="TextBoxPlaceholderTextThemeBrush" Color="#AB000000" />
@@ -451,7 +537,7 @@
     <SolidColorBrush x:Key="RadioButtonPressedBorderThemeBrush" Color="#FFFFFFFF" />
     <SolidColorBrush x:Key="RadioButtonPressedForegroundThemeBrush" Color="#FF000000" />
     <SolidColorBrush x:Key="RadioButtonContentPointerOverForegroundThemeBrush" Color="{DynamicResource SystemColorHighlightTextColor}" />
-    
+
     <!-- Resources for Slider.xaml -->
     <x:Double x:Key="SliderOutsideTickBarThemeHeight">4</x:Double>
     <x:Double x:Key="SliderTrackThemeHeight">2</x:Double>
@@ -502,6 +588,65 @@
     <SolidColorBrush x:Key="SliderTrackPressedBackgroundThemeBrush" Color="#59FFFFFF" />
     <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 -->
     <x:Double x:Key="ToolTipContentThemeFontSize">12</x:Double>
     <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">
   <Style.Resources>
     <!-- Resources for Button.xaml -->
@@ -181,8 +181,8 @@
     <StaticResource x:Key="ComboBoxDropDownGlyphForeground" ResourceKey="SystemControlForegroundBaseMediumHighBrush" />
     <StaticResource x:Key="ComboBoxDropDownGlyphForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
     <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="ComboBoxDropDownBorderBrush" ResourceKey="SystemControlTransientBorderBrush" />
 
@@ -230,7 +230,7 @@
     <StaticResource x:Key="ComboBoxFocusedDropDownBackgroundPointerOver" ResourceKey="SystemControlBackgroundBaseLowBrush" />
     <StaticResource x:Key="ComboBoxFocusedDropDownBackgroundPointerPressed" ResourceKey="SystemControlBackgroundBaseMediumLowBrush" />
     <StaticResource x:Key="ComboBoxEditableDropDownGlyphForeground" ResourceKey="SystemControlForegroundBaseMediumHighBrush" />
-    
+
     <!-- Resources for ListBox.xaml -->
     <Thickness x:Key="ListBoxBorderThemeThickness">0</Thickness>
     <SolidColorBrush x:Key="ListBoxBackgroundThemeBrush" Color="#CCFFFFFF" />
@@ -249,6 +249,91 @@
     <SolidColorBrush x:Key="ListBoxItemSelectedForegroundThemeBrush" Color="White" />
     <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 -->
     <SolidColorBrush x:Key="TextBoxForegroundHeaderThemeBrush" Color="#FF000000" />
     <SolidColorBrush x:Key="TextBoxPlaceholderTextThemeBrush" Color="#AB000000" />
@@ -450,7 +535,7 @@
     <SolidColorBrush x:Key="RadioButtonPressedBorderThemeBrush" Color="#FF000000" />
     <SolidColorBrush x:Key="RadioButtonPressedForegroundThemeBrush" Color="#FFFFFFFF" />
     <SolidColorBrush x:Key="RadioButtonContentPointerOverForegroundThemeBrush" Color="{DynamicResource SystemColorHighlightTextColor}" />
-    
+
     <!-- Resources for Slider.xaml -->
     <x:Double x:Key="SliderOutsideTickBarThemeHeight">4</x:Double>
     <x:Double x:Key="SliderTrackThemeHeight">2</x:Double>
@@ -501,6 +586,65 @@
     <SolidColorBrush x:Key="SliderTrackPressedBackgroundThemeBrush" Color="#33000000" />
     <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 -->
     <x:Double x:Key="ToolTipContentThemeFontSize">12</x:Double>
     <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>
       <Border Background="{TemplateBinding Background}"
               BorderBrush="{TemplateBinding BorderBrush}"
               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>
     </ControlTemplate>
   </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.NotificationCard.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>

+ 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">
     <ControlTemplate>
       <Border Background="{TemplateBinding Background}"
               BorderBrush="{TemplateBinding BorderBrush}"
               BorderThickness="{TemplateBinding BorderThickness}"
+              HorizontalAlignment="Stretch"
               Padding="{TemplateBinding Padding}">
-        <ItemsPresenter Name="PART_ItemsPresenter" 
-                        Items="{TemplateBinding Items}" 
+        <ItemsPresenter Name="PART_ItemsPresenter"
+                        Items="{TemplateBinding Items}"
                         ItemsPanel="{TemplateBinding ItemsPanel}"
                         ItemTemplate="{TemplateBinding ItemTemplate}"
-                        KeyboardNavigation.TabNavigation="Continue"/>
+                        VerticalAlignment="Stretch"
+                        KeyboardNavigation.TabNavigation="Continue" />
       </Border>
     </ControlTemplate>
   </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:conv="clr-namespace:Avalonia.Controls.Converters;assembly=Avalonia.Controls"
         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>
-    <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>
+
   <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">
       <ControlTemplate>
-        <Border Name="root"
+        <Border Name="PART_LayoutRoot"
+                Padding="{TemplateBinding Padding}"
                 Background="{TemplateBinding Background}"
                 BorderBrush="{TemplateBinding BorderBrush}"
                 BorderThickness="{TemplateBinding BorderThickness}">
           <Grid>
             <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>
-            <ContentPresenter Name="icon"
+            <ContentPresenter Name="PART_IconPresenter"
                               Content="{TemplateBinding Icon}"
                               Width="16"
                               Height="16"
-                              Margin="3"
+                              Margin="{DynamicResource MenuIconPresenterMargin}"
                               HorizontalAlignment="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"
                               Content="{TemplateBinding Header}"
-                              Margin="{TemplateBinding Padding}"
                               VerticalAlignment="Center"
-                              Grid.Column="2">
+                              HorizontalAlignment="Stretch"
+                              TextBlock.Foreground="{TemplateBinding Foreground}"
+                              Grid.Column="1">
               <ContentPresenter.DataTemplates>
                 <DataTemplate DataType="sys:String">
-                  <AccessText Text="{Binding}"/>
+                  <AccessText Text="{Binding}" />
                 </DataTemplate>
               </ContentPresenter.DataTemplates>
             </ContentPresenter>
             <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"
-                  Grid.Column="4"/>
+                  Grid.Column="3" />
             <Popup Name="PART_Popup"
+                   WindowManagerAddShadowHint="True"
                    PlacementMode="Right"
                    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>
               </Border>
             </Popup>
-            </Grid>
+          </Grid>
         </Border>
       </ControlTemplate>
     </Setter>
   </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">
-    <Setter Property="Padding" Value="6 0"/>
     <Setter Property="Template">
       <ControlTemplate>
-        <Border Name="root"
+        <Border Name="PART_LayoutRoot"
                 Background="{TemplateBinding Background}"
                 BorderBrush="{TemplateBinding BorderBrush}"
                 BorderThickness="{TemplateBinding BorderThickness}">
@@ -103,22 +148,31 @@
                               Margin="{TemplateBinding Padding}">
               <ContentPresenter.DataTemplates>
                 <DataTemplate DataType="sys:String">
-                  <AccessText Text="{Binding}"/>
+                  <AccessText Text="{Binding}" />
                 </DataTemplate>
               </ContentPresenter.DataTemplates>
             </ContentPresenter>
             <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">
-              <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>
                   <ItemsPresenter Name="PART_ItemsPresenter"
                                   Items="{TemplateBinding Items}"
                                   ItemsPanel="{TemplateBinding ItemsPanel}"
                                   ItemTemplate="{TemplateBinding ItemTemplate}"
-                                  Grid.IsSharedSizeScope="True"/>
+                                  Margin="{DynamicResource MenuFlyoutScrollerMargin}"
+                                  Grid.IsSharedSizeScope="True" />
                 </ScrollViewer>
               </Border>
             </Popup>
@@ -128,20 +182,78 @@
     </Setter>
   </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 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 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 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>
 </Styles>

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

@@ -4,17 +4,15 @@
     <Setter Property="Focusable" Value="False"/>
     <Setter Property="Template">
       <ControlTemplate>
-        <Border BorderBrush="{TemplateBinding BorderBrush}"
+        <Border Padding="{TemplateBinding Margin}"
+                Height="{TemplateBinding Height}"
+                HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
+                VerticalAlignment="{TemplateBinding VerticalAlignment}"
+                BorderBrush="{TemplateBinding BorderBrush}"
                 BorderThickness="{TemplateBinding BorderThickness}"
                 Background="{TemplateBinding Background}"/>
       </ControlTemplate>
     </Setter>
   </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>

+ 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;
             _x11 = platform.Info;
-            _multitouch = platform.Options?.EnableMultiTouch ?? false;
+            _multitouch = platform.Options?.EnableMultiTouch ?? true;
             var devices =(XIDeviceInfo*) XIQueryDevice(_x11.Display,
                 (int)XiPredefinedDeviceId.XIAllMasterDevices, out int num);
             for (var c = 0; c < num; c++)
@@ -237,6 +237,22 @@ namespace Avalonia.X11
                         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)
             {
                 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);
 
-            _multitouch = Win32Platform.Options.EnableMultitouch ?? false;
+            _multitouch = Win32Platform.Options.EnableMultitouch ?? true;
 
             if (_multitouch)
             {