Pārlūkot izejas kodu

Merge branch 'master' into fixes/5475-submenu-interaction

Dan Walmsley 4 gadi atpakaļ
vecāks
revīzija
87cc3fcded

+ 2 - 0
native/Avalonia.Native/src/OSX/common.h

@@ -28,6 +28,8 @@ extern IAvnNativeControlHost* CreateNativeControlHost(NSView* parent);
 extern void SetAppMenu (NSString* appName, IAvnMenu* appMenu);
 extern void SetAppMenu (NSString* appName, IAvnMenu* appMenu);
 extern IAvnMenu* GetAppMenu ();
 extern IAvnMenu* GetAppMenu ();
 extern NSMenuItem* GetAppMenuItem ();
 extern NSMenuItem* GetAppMenuItem ();
+extern void SetAutoGenerateDefaultAppMenuItems (bool enabled);
+extern bool GetAutoGenerateDefaultAppMenuItems ();
 
 
 extern void InitializeAvnApp();
 extern void InitializeAvnApp();
 extern NSApplicationActivationPolicy AvnDesiredActivationPolicy;
 extern NSApplicationActivationPolicy AvnDesiredActivationPolicy;

+ 17 - 0
native/Avalonia.Native/src/OSX/main.mm

@@ -2,6 +2,7 @@
 #define COM_GUIDS_MATERIALIZE
 #define COM_GUIDS_MATERIALIZE
 #include "common.h"
 #include "common.h"
 
 
+static bool s_generateDefaultAppMenuItems = true;
 static NSString* s_appTitle = @"Avalonia";
 static NSString* s_appTitle = @"Avalonia";
 
 
 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
@@ -122,6 +123,12 @@ public:
             ? NSApplicationActivationPolicyRegular : NSApplicationActivationPolicyAccessory;
             ? NSApplicationActivationPolicyRegular : NSApplicationActivationPolicyAccessory;
         return S_OK;
         return S_OK;
     }
     }
+    
+    virtual HRESULT SetDisableDefaultApplicationMenuItems (bool enabled) override
+    {
+        SetAutoGenerateDefaultAppMenuItems(!enabled);
+        return S_OK;
+    }
 };
 };
 
 
 /// See "Using POSIX Threads in a Cocoa Application" section here:
 /// See "Using POSIX Threads in a Cocoa Application" section here:
@@ -310,3 +317,13 @@ CGFloat PrimaryDisplayHeight()
 {
 {
   return NSMaxY([[[NSScreen screens] firstObject] frame]);
   return NSMaxY([[[NSScreen screens] firstObject] frame]);
 }
 }
+
+void SetAutoGenerateDefaultAppMenuItems (bool enabled)
+{
+    s_generateDefaultAppMenuItems = enabled;
+}
+
+bool GetAutoGenerateDefaultAppMenuItems ()
+{
+    return s_generateDefaultAppMenuItems;
+}

+ 44 - 41
native/Avalonia.Native/src/OSX/menu.mm

@@ -445,47 +445,50 @@ extern void SetAppMenu (NSString* appName, IAvnMenu* menu)
         
         
         auto appMenu  = [s_appMenuItem submenu];
         auto appMenu  = [s_appMenuItem submenu];
         
         
-        [appMenu addItem:[NSMenuItem separatorItem]];
-        
-        // Services item and menu
-        auto servicesItem = [[NSMenuItem alloc] init];
-        servicesItem.title = @"Services";
-        NSMenu *servicesMenu = [[NSMenu alloc] initWithTitle:@"Services"];
-        servicesItem.submenu = servicesMenu;
-        [NSApplication sharedApplication].servicesMenu = servicesMenu;
-        [appMenu addItem:servicesItem];
-        
-        [appMenu addItem:[NSMenuItem separatorItem]];
-        
-        // Hide Application
-        auto hideItem = [[NSMenuItem alloc] initWithTitle:[@"Hide " stringByAppendingString:appName] action:@selector(hide:) keyEquivalent:@"h"];
-        
-        [appMenu addItem:hideItem];
-        
-        // Hide Others
-        auto hideAllOthersItem = [[NSMenuItem alloc] initWithTitle:@"Hide Others"
-                                                       action:@selector(hideOtherApplications:)
-                                                keyEquivalent:@"h"];
-        
-        hideAllOthersItem.keyEquivalentModifierMask = NSEventModifierFlagCommand | NSEventModifierFlagOption;
-        [appMenu addItem:hideAllOthersItem];
-        
-        // Show All
-        auto showAllItem = [[NSMenuItem alloc] initWithTitle:@"Show All"
-                                                 action:@selector(unhideAllApplications:)
-                                          keyEquivalent:@""];
-        
-        [appMenu addItem:showAllItem];
-        
-        [appMenu addItem:[NSMenuItem separatorItem]];
-        
-        // Quit Application
-        auto quitItem = [[NSMenuItem alloc] init];
-        quitItem.title = [@"Quit " stringByAppendingString:appName];
-        quitItem.keyEquivalent = @"q";
-        quitItem.target = [AvnWindow class];
-        quitItem.action = @selector(closeAll);
-        [appMenu addItem:quitItem];
+        if(GetAutoGenerateDefaultAppMenuItems())
+        {
+            [appMenu addItem:[NSMenuItem separatorItem]];
+            
+            // Services item and menu
+            auto servicesItem = [[NSMenuItem alloc] init];
+            servicesItem.title = @"Services";
+            NSMenu *servicesMenu = [[NSMenu alloc] initWithTitle:@"Services"];
+            servicesItem.submenu = servicesMenu;
+            [NSApplication sharedApplication].servicesMenu = servicesMenu;
+            [appMenu addItem:servicesItem];
+            
+            [appMenu addItem:[NSMenuItem separatorItem]];
+            
+            // Hide Application
+            auto hideItem = [[NSMenuItem alloc] initWithTitle:[@"Hide " stringByAppendingString:appName] action:@selector(hide:) keyEquivalent:@"h"];
+            
+            [appMenu addItem:hideItem];
+            
+            // Hide Others
+            auto hideAllOthersItem = [[NSMenuItem alloc] initWithTitle:@"Hide Others"
+                                                           action:@selector(hideOtherApplications:)
+                                                    keyEquivalent:@"h"];
+            
+            hideAllOthersItem.keyEquivalentModifierMask = NSEventModifierFlagCommand | NSEventModifierFlagOption;
+            [appMenu addItem:hideAllOthersItem];
+            
+            // Show All
+            auto showAllItem = [[NSMenuItem alloc] initWithTitle:@"Show All"
+                                                     action:@selector(unhideAllApplications:)
+                                              keyEquivalent:@""];
+            
+            [appMenu addItem:showAllItem];
+            
+            [appMenu addItem:[NSMenuItem separatorItem]];
+            
+            // Quit Application
+            auto quitItem = [[NSMenuItem alloc] init];
+            quitItem.title = [@"Quit " stringByAppendingString:appName];
+            quitItem.keyEquivalent = @"q";
+            quitItem.target = [AvnWindow class];
+            quitItem.action = @selector(closeAll);
+            [appMenu addItem:quitItem];
+        }
     }
     }
     else
     else
     {
     {

+ 4 - 4
samples/ControlCatalog/Pages/AcrylicPage.xaml

@@ -16,13 +16,13 @@
         <StackPanel Spacing="5" Margin="40 10">
         <StackPanel Spacing="5" Margin="40 10">
           <StackPanel Orientation="Horizontal">
           <StackPanel Orientation="Horizontal">
             <TextBlock Text="TintOpacity" Foreground="Black" />
             <TextBlock Text="TintOpacity" Foreground="Black" />
-            <Slider Name="TintOpacitySlider" Minimum="0" Maximum="1" Value="0.9" Width="400" />
-            <TextBlock Text="{Binding #TintOpacitySlider.Value}" Foreground="Black" />
+            <Slider Name="TintOpacitySlider" Minimum="0" Maximum="1" Value="0.9" SmallChange="0.1" LargeChange="0.2" Width="400" />
+            <TextBlock Text="{Binding #TintOpacitySlider.Value, StringFormat=\{0:0.#\}}" Foreground="Black" />
           </StackPanel>
           </StackPanel>
           <StackPanel Orientation="Horizontal">
           <StackPanel Orientation="Horizontal">
             <TextBlock Text="MaterialOpacity" Foreground="Black" />
             <TextBlock Text="MaterialOpacity" Foreground="Black" />
-            <Slider Name="MaterialOpacitySlider" Minimum="0" Maximum="1" Value="0.8" Width="400" />
-            <TextBlock Text="{Binding #MaterialOpacitySlider.Value}" Foreground="Black" />
+            <Slider Name="MaterialOpacitySlider" Minimum="0" Maximum="1" Value="0.8" SmallChange="0.1" LargeChange="0.2" Width="400" />
+            <TextBlock Text="{Binding #MaterialOpacitySlider.Value, StringFormat=\{0:0.#\}}" Foreground="Black" />
           </StackPanel>
           </StackPanel>
         </StackPanel>
         </StackPanel>
       </ExperimentalAcrylicBorder>
       </ExperimentalAcrylicBorder>

+ 15 - 0
samples/ControlCatalog/Pages/SliderPage.xaml

@@ -45,6 +45,12 @@
             <sys:Exception /> 
             <sys:Exception /> 
           </DataValidationErrors.Error>
           </DataValidationErrors.Error>
         </Slider>
         </Slider>
+        <Slider Value="0"
+                IsDirectionReversed="True"
+                Minimum="0"
+                Maximum="100"
+                TickFrequency="10"
+                Width="300" />
       </StackPanel>
       </StackPanel>
       <Slider Value="0"
       <Slider Value="0"
               Minimum="0"
               Minimum="0"
@@ -54,6 +60,15 @@
               TickPlacement="Outside"
               TickPlacement="Outside"
               TickFrequency="10"
               TickFrequency="10"
               Height="300"/>
               Height="300"/>
+      <Slider Value="0"
+              IsDirectionReversed="True"
+              Minimum="0"
+              Maximum="100"
+              Orientation="Vertical"
+              IsSnapToTickEnabled="True"
+              TickPlacement="Outside"
+              TickFrequency="10"
+              Height="300"/>
     </StackPanel>
     </StackPanel>
 
 
   </StackPanel>
   </StackPanel>

+ 8 - 8
src/Avalonia.Animation/Animation.cs

@@ -22,7 +22,7 @@ namespace Avalonia.Animation
         /// </summary>
         /// </summary>
         public static readonly DirectProperty<Animation, TimeSpan> DurationProperty =
         public static readonly DirectProperty<Animation, TimeSpan> DurationProperty =
             AvaloniaProperty.RegisterDirect<Animation, TimeSpan>(
             AvaloniaProperty.RegisterDirect<Animation, TimeSpan>(
-                nameof(_duration),
+                nameof(Duration),
                 o => o._duration,
                 o => o._duration,
                 (o, v) => o._duration = v);
                 (o, v) => o._duration = v);
 
 
@@ -31,7 +31,7 @@ namespace Avalonia.Animation
         /// </summary>
         /// </summary>
         public static readonly DirectProperty<Animation, IterationCount> IterationCountProperty =
         public static readonly DirectProperty<Animation, IterationCount> IterationCountProperty =
             AvaloniaProperty.RegisterDirect<Animation, IterationCount>(
             AvaloniaProperty.RegisterDirect<Animation, IterationCount>(
-                nameof(_iterationCount),
+                nameof(IterationCount),
                 o => o._iterationCount,
                 o => o._iterationCount,
                 (o, v) => o._iterationCount = v);
                 (o, v) => o._iterationCount = v);
 
 
@@ -40,7 +40,7 @@ namespace Avalonia.Animation
         /// </summary>
         /// </summary>
         public static readonly DirectProperty<Animation, PlaybackDirection> PlaybackDirectionProperty =
         public static readonly DirectProperty<Animation, PlaybackDirection> PlaybackDirectionProperty =
             AvaloniaProperty.RegisterDirect<Animation, PlaybackDirection>(
             AvaloniaProperty.RegisterDirect<Animation, PlaybackDirection>(
-                nameof(_playbackDirection),
+                nameof(PlaybackDirection),
                 o => o._playbackDirection,
                 o => o._playbackDirection,
                 (o, v) => o._playbackDirection = v);
                 (o, v) => o._playbackDirection = v);
 
 
@@ -49,7 +49,7 @@ namespace Avalonia.Animation
         /// </summary>
         /// </summary>
         public static readonly DirectProperty<Animation, FillMode> FillModeProperty =
         public static readonly DirectProperty<Animation, FillMode> FillModeProperty =
             AvaloniaProperty.RegisterDirect<Animation, FillMode>(
             AvaloniaProperty.RegisterDirect<Animation, FillMode>(
-                nameof(_fillMode),
+                nameof(FillMode),
                 o => o._fillMode,
                 o => o._fillMode,
                 (o, v) => o._fillMode = v);
                 (o, v) => o._fillMode = v);
 
 
@@ -58,7 +58,7 @@ namespace Avalonia.Animation
         /// </summary>
         /// </summary>
         public static readonly DirectProperty<Animation, Easing> EasingProperty =
         public static readonly DirectProperty<Animation, Easing> EasingProperty =
             AvaloniaProperty.RegisterDirect<Animation, Easing>(
             AvaloniaProperty.RegisterDirect<Animation, Easing>(
-                nameof(_easing),
+                nameof(Easing),
                 o => o._easing,
                 o => o._easing,
                 (o, v) => o._easing = v);
                 (o, v) => o._easing = v);
 
 
@@ -67,7 +67,7 @@ namespace Avalonia.Animation
         /// </summary>
         /// </summary>
         public static readonly DirectProperty<Animation, TimeSpan> DelayProperty =
         public static readonly DirectProperty<Animation, TimeSpan> DelayProperty =
             AvaloniaProperty.RegisterDirect<Animation, TimeSpan>(
             AvaloniaProperty.RegisterDirect<Animation, TimeSpan>(
-                nameof(_delay),
+                nameof(Delay),
                 o => o._delay,
                 o => o._delay,
                 (o, v) => o._delay = v);
                 (o, v) => o._delay = v);
 
 
@@ -76,7 +76,7 @@ namespace Avalonia.Animation
         /// </summary>
         /// </summary>
         public static readonly DirectProperty<Animation, TimeSpan> DelayBetweenIterationsProperty =
         public static readonly DirectProperty<Animation, TimeSpan> DelayBetweenIterationsProperty =
             AvaloniaProperty.RegisterDirect<Animation, TimeSpan>(
             AvaloniaProperty.RegisterDirect<Animation, TimeSpan>(
-                nameof(_delayBetweenIterations),
+                nameof(DelayBetweenIterations),
                 o => o._delayBetweenIterations,
                 o => o._delayBetweenIterations,
                 (o, v) => o._delayBetweenIterations = v);
                 (o, v) => o._delayBetweenIterations = v);
 
 
@@ -85,7 +85,7 @@ namespace Avalonia.Animation
         /// </summary>
         /// </summary>
         public static readonly DirectProperty<Animation, double> SpeedRatioProperty =
         public static readonly DirectProperty<Animation, double> SpeedRatioProperty =
             AvaloniaProperty.RegisterDirect<Animation, double>(
             AvaloniaProperty.RegisterDirect<Animation, double>(
-                nameof(_speedRatio),
+                nameof(SpeedRatio),
                 o => o._speedRatio,
                 o => o._speedRatio,
                 (o, v) => o._speedRatio = v,
                 (o, v) => o._speedRatio = v,
                 defaultBindingMode: BindingMode.TwoWay);
                 defaultBindingMode: BindingMode.TwoWay);

+ 2 - 0
src/Avalonia.Controls.DataGrid/DataGridTemplateColumn.cs

@@ -8,6 +8,7 @@ using Avalonia.Controls.Utils;
 using Avalonia.Input;
 using Avalonia.Input;
 using Avalonia.Interactivity;
 using Avalonia.Interactivity;
 using Avalonia.Media;
 using Avalonia.Media;
+using Avalonia.Metadata;
 using Avalonia.Utilities;
 using Avalonia.Utilities;
 
 
 namespace Avalonia.Controls
 namespace Avalonia.Controls
@@ -22,6 +23,7 @@ namespace Avalonia.Controls
                 o => o.CellTemplate,
                 o => o.CellTemplate,
                 (o, v) => o.CellTemplate = v);
                 (o, v) => o.CellTemplate = v);
 
 
+        [Content]
         public IDataTemplate CellTemplate
         public IDataTemplate CellTemplate
         {
         {
             get { return _cellTemplate; }
             get { return _cellTemplate; }

+ 52 - 3
src/Avalonia.Controls/Generators/TabItemContainerGenerator.cs

@@ -1,4 +1,10 @@
+using System;
+using System.Collections.Generic;
 using Avalonia.Controls.Primitives;
 using Avalonia.Controls.Primitives;
+using Avalonia.Controls.Templates;
+using Avalonia.LogicalTree;
+using Avalonia.Reactive;
+using Avalonia.VisualTree;
 
 
 namespace Avalonia.Controls.Generators
 namespace Avalonia.Controls.Generators
 {    
 {    
@@ -16,11 +22,15 @@ namespace Avalonia.Controls.Generators
         {
         {
             var tabItem = (TabItem)base.CreateContainer(item);
             var tabItem = (TabItem)base.CreateContainer(item);
 
 
-            tabItem[~TabControl.TabStripPlacementProperty] = Owner[~TabControl.TabStripPlacementProperty];
+            tabItem.Bind(TabItem.TabStripPlacementProperty, new OwnerBinding<Dock>(
+                tabItem,
+                TabControl.TabStripPlacementProperty));
 
 
             if (tabItem.HeaderTemplate == null)
             if (tabItem.HeaderTemplate == null)
             {
             {
-                tabItem[~HeaderedContentControl.HeaderTemplateProperty] = Owner[~ItemsControl.ItemTemplateProperty];
+                tabItem.Bind(TabItem.HeaderTemplateProperty, new OwnerBinding<IDataTemplate>(
+                    tabItem,
+                    TabControl.ItemTemplateProperty));
             }
             }
 
 
             if (tabItem.Header == null)
             if (tabItem.Header == null)
@@ -40,10 +50,49 @@ namespace Avalonia.Controls.Generators
 
 
             if (!(tabItem.Content is IControl))
             if (!(tabItem.Content is IControl))
             {
             {
-                tabItem[~ContentControl.ContentTemplateProperty] = Owner[~TabControl.ContentTemplateProperty];
+                tabItem.Bind(TabItem.ContentTemplateProperty, new OwnerBinding<IDataTemplate>(
+                    tabItem,
+                    TabControl.ContentTemplateProperty));
             }
             }
 
 
             return tabItem;
             return tabItem;
         }
         }
+
+        private class OwnerBinding<T> : SingleSubscriberObservableBase<T>
+        {
+            private readonly TabItem _item;
+            private readonly StyledProperty<T> _ownerProperty;
+            private IDisposable _ownerSubscription;
+            private IDisposable _propertySubscription;
+
+            public OwnerBinding(TabItem item, StyledProperty<T> ownerProperty)
+            {
+                _item = item;
+                _ownerProperty = ownerProperty;
+            }
+
+            protected override void Subscribed()
+            {
+                _ownerSubscription = ControlLocator.Track(_item, 0, typeof(TabControl)).Subscribe(OwnerChanged);
+            }
+
+            protected override void Unsubscribed()
+            {
+                _ownerSubscription?.Dispose();
+                _ownerSubscription = null;
+            }
+
+            private void OwnerChanged(ILogical c)
+            {
+                _propertySubscription?.Dispose();
+                _propertySubscription = null;
+
+                if (c is TabControl tabControl)
+                {
+                    _propertySubscription = tabControl.GetObservable(_ownerProperty)
+                        .Subscribe(x => PublishNext(x));
+                }
+            }
+        }
     }
     }
 }
 }

+ 5 - 1
src/Avalonia.Controls/NativeControlHost.cs

@@ -157,10 +157,14 @@ namespace Avalonia.Controls
             var needsShow = IsEffectivelyVisible && bounds.HasValue;
             var needsShow = IsEffectivelyVisible && bounds.HasValue;
 
 
             if (needsShow)
             if (needsShow)
+            {
+                if (bounds.Value.IsEmpty)
+                    return false;
                 _attachment?.ShowInBounds(bounds.Value);
                 _attachment?.ShowInBounds(bounds.Value);
+            }
             else
             else
                 _attachment?.HideWithSize(Bounds.Size);
                 _attachment?.HideWithSize(Bounds.Size);
-            return false;
+            return true;
         }
         }
 
 
         private void CheckDestruction()
         private void CheckDestruction()

+ 38 - 9
src/Avalonia.Controls/Slider.cs

@@ -49,6 +49,12 @@ namespace Avalonia.Controls
         public static readonly StyledProperty<Orientation> OrientationProperty =
         public static readonly StyledProperty<Orientation> OrientationProperty =
             ScrollBar.OrientationProperty.AddOwner<Slider>();
             ScrollBar.OrientationProperty.AddOwner<Slider>();
 
 
+        /// <summary>
+        /// Defines the <see cref="IsDirectionReversed"/> property.
+        /// </summary>
+        public static readonly StyledProperty<bool> IsDirectionReversedProperty =
+            Track.IsDirectionReversedProperty.AddOwner<Slider>();
+
         /// <summary>
         /// <summary>
         /// Defines the <see cref="IsSnapToTickEnabled"/> property.
         /// Defines the <see cref="IsSnapToTickEnabled"/> property.
         /// </summary>
         /// </summary>
@@ -83,7 +89,6 @@ namespace Avalonia.Controls
         private IDisposable _increaseButtonSubscription;
         private IDisposable _increaseButtonSubscription;
         private IDisposable _increaseButtonReleaseDispose;
         private IDisposable _increaseButtonReleaseDispose;
         private IDisposable _pointerMovedDispose;
         private IDisposable _pointerMovedDispose;
-        private IDisposable _trackOnKeyDownDispose;
 
 
         private const double Tolerance = 0.0001;
         private const double Tolerance = 0.0001;
 
 
@@ -93,6 +98,7 @@ namespace Avalonia.Controls
         static Slider()
         static Slider()
         {
         {
             PressedMixin.Attach<Slider>();
             PressedMixin.Attach<Slider>();
+            FocusableProperty.OverrideDefaultValue<Slider>(true);
             OrientationProperty.OverrideDefaultValue(typeof(Slider), Orientation.Horizontal);
             OrientationProperty.OverrideDefaultValue(typeof(Slider), Orientation.Horizontal);
             Thumb.DragStartedEvent.AddClassHandler<Slider>((x, e) => x.OnThumbDragStarted(e), RoutingStrategies.Bubble);
             Thumb.DragStartedEvent.AddClassHandler<Slider>((x, e) => x.OnThumbDragStarted(e), RoutingStrategies.Bubble);
             Thumb.DragCompletedEvent.AddClassHandler<Slider>((x, e) => x.OnThumbDragCompleted(e),
             Thumb.DragCompletedEvent.AddClassHandler<Slider>((x, e) => x.OnThumbDragCompleted(e),
@@ -127,6 +133,19 @@ namespace Avalonia.Controls
             set { SetValue(OrientationProperty, value); }
             set { SetValue(OrientationProperty, value); }
         }
         }
 
 
+        /// <summary>
+        /// Gets or sets the direction of increasing value.
+        /// </summary>
+        /// <value>
+        /// true if the direction of increasing value is to the left for a horizontal slider or
+        /// down for a vertical slider; otherwise, false. The default is false.
+        /// </value>
+        public bool IsDirectionReversed
+        {
+            get { return GetValue(IsDirectionReversedProperty); }
+            set { SetValue(IsDirectionReversedProperty, value); }
+        }
+
         /// <summary>
         /// <summary>
         /// Gets or sets a value that indicates whether the <see cref="Slider"/> automatically moves the <see cref="Thumb"/> to the closest tick mark.
         /// Gets or sets a value that indicates whether the <see cref="Slider"/> automatically moves the <see cref="Thumb"/> to the closest tick mark.
         /// </summary>
         /// </summary>
@@ -165,7 +184,6 @@ namespace Avalonia.Controls
             _increaseButtonSubscription?.Dispose();
             _increaseButtonSubscription?.Dispose();
             _increaseButtonReleaseDispose?.Dispose();
             _increaseButtonReleaseDispose?.Dispose();
             _pointerMovedDispose?.Dispose();
             _pointerMovedDispose?.Dispose();
-            _trackOnKeyDownDispose?.Dispose();
             
             
             _decreaseButton = e.NameScope.Find<Button>("PART_DecreaseButton");
             _decreaseButton = e.NameScope.Find<Button>("PART_DecreaseButton");
             _track = e.NameScope.Find<Track>("PART_Track");
             _track = e.NameScope.Find<Track>("PART_Track");
@@ -174,7 +192,6 @@ namespace Avalonia.Controls
             if (_track != null)
             if (_track != null)
             {
             {
                 _track.IsThumbDragHandled = true;
                 _track.IsThumbDragHandled = true;
-                _trackOnKeyDownDispose = _track.AddDisposableHandler(KeyDownEvent, TrackOnKeyDown);
             }
             }
 
 
             if (_decreaseButton != null)
             if (_decreaseButton != null)
@@ -192,26 +209,32 @@ namespace Avalonia.Controls
             _pointerMovedDispose = this.AddDisposableHandler(PointerMovedEvent, TrackMoved, RoutingStrategies.Tunnel);
             _pointerMovedDispose = this.AddDisposableHandler(PointerMovedEvent, TrackMoved, RoutingStrategies.Tunnel);
         }
         }
 
 
-        private void TrackOnKeyDown(object sender, KeyEventArgs e)
+        protected override void OnKeyDown(KeyEventArgs e)
         {
         {
-            if (e.KeyModifiers != KeyModifiers.None) return;
+            base.OnKeyDown(e);
+
+            if (e.Handled || e.KeyModifiers != KeyModifiers.None) return;
+
+            var handled = true;
 
 
             switch (e.Key)
             switch (e.Key)
             {
             {
+                case Key.Down:
                 case Key.Left:
                 case Key.Left:
-                    MoveToNextTick(-SmallChange);
+                    MoveToNextTick(IsDirectionReversed ? SmallChange : -SmallChange);
                     break;
                     break;
 
 
+                case Key.Up:
                 case Key.Right:
                 case Key.Right:
-                    MoveToNextTick(SmallChange);
+                    MoveToNextTick(IsDirectionReversed ? -SmallChange : SmallChange);
                     break;
                     break;
 
 
                 case Key.PageUp:
                 case Key.PageUp:
-                    MoveToNextTick(-LargeChange);
+                    MoveToNextTick(IsDirectionReversed ? -LargeChange : LargeChange);
                     break;
                     break;
 
 
                 case Key.PageDown:
                 case Key.PageDown:
-                    MoveToNextTick(LargeChange);
+                    MoveToNextTick(IsDirectionReversed ? LargeChange : -LargeChange);
                     break;
                     break;
 
 
                 case Key.Home:
                 case Key.Home:
@@ -221,7 +244,13 @@ namespace Avalonia.Controls
                 case Key.End:
                 case Key.End:
                     Value = Maximum;
                     Value = Maximum;
                     break;
                     break;
+
+                default:
+                    handled = false;
+                    break;
             }
             }
+
+            e.Handled = handled;
         }
         }
             
             
         private void MoveToNextTick(double direction)
         private void MoveToNextTick(double direction)

+ 1 - 1
src/Avalonia.Layout/UniformGridLayout.cs

@@ -447,7 +447,7 @@ namespace Avalonia.Layout
             // and only use the layout when to clear it when it's done.
             // and only use the layout when to clear it when it's done.
             gridState.EnsureFirstElementOwnership(context);
             gridState.EnsureFirstElementOwnership(context);
 
 
-            return new Size(desiredSize.Width, desiredSize.Height);
+            return desiredSize;
         }
         }
 
 
         protected internal override Size ArrangeOverride(VirtualizingLayoutContext context, Size finalSize)
         protected internal override Size ArrangeOverride(VirtualizingLayoutContext context, Size finalSize)

+ 2 - 0
src/Avalonia.Native/AvaloniaNativePlatform.cs

@@ -92,6 +92,8 @@ namespace Avalonia.Native
                 var macOpts = AvaloniaLocator.Current.GetService<MacOSPlatformOptions>();
                 var macOpts = AvaloniaLocator.Current.GetService<MacOSPlatformOptions>();
 
 
                 _factory.MacOptions.SetShowInDock(macOpts?.ShowInDock != false ? 1 : 0);
                 _factory.MacOptions.SetShowInDock(macOpts?.ShowInDock != false ? 1 : 0);
+                _factory.MacOptions.SetDisableDefaultApplicationMenuItems(
+                    macOpts?.DisableDefaultApplicationMenuItems == true ? 1 : 0);
             }
             }
 
 
             AvaloniaLocator.CurrentMutable
             AvaloniaLocator.CurrentMutable

+ 2 - 0
src/Avalonia.Native/AvaloniaNativePlatformExtensions.cs

@@ -38,5 +38,7 @@ namespace Avalonia
     public class MacOSPlatformOptions
     public class MacOSPlatformOptions
     {
     {
         public bool ShowInDock { get; set; } = true;
         public bool ShowInDock { get; set; } = true;
+        
+        public bool DisableDefaultApplicationMenuItems { get; set; }
     }
     }
 }
 }

+ 1 - 0
src/Avalonia.Native/avn.idl

@@ -528,6 +528,7 @@ interface IAvnMacOptions : IUnknown
 {
 {
      HRESULT SetShowInDock(int show);
      HRESULT SetShowInDock(int show);
      HRESULT SetApplicationTitle(char* utf8string);
      HRESULT SetApplicationTitle(char* utf8string);
+     HRESULT SetDisableDefaultApplicationMenuItems(bool enabled);
 }
 }
 
 
 [uuid(04c1b049-1f43-418a-9159-cae627ec1367)]
 [uuid(04c1b049-1f43-418a-9159-cae627ec1367)]

+ 3 - 2
src/Avalonia.Themes.Default/Slider.xaml

@@ -11,7 +11,7 @@
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
           </Grid.RowDefinitions>
           </Grid.RowDefinitions>
           <Border Name="TrackBackground" Grid.Row="1" Height="4" Margin="6,0" VerticalAlignment="Center"/>
           <Border Name="TrackBackground" Grid.Row="1" Height="4" Margin="6,0" VerticalAlignment="Center"/>
-          <Track Name="PART_Track" Grid.Row="1" Orientation="Horizontal">
+          <Track Name="PART_Track" Grid.Row="1" IsDirectionReversed="{TemplateBinding IsDirectionReversed}" Orientation="Horizontal">
             <Track.DecreaseButton>
             <Track.DecreaseButton>
                <RepeatButton Name="PART_DecreaseButton"
                <RepeatButton Name="PART_DecreaseButton"
                              Classes="repeattrack" />
                              Classes="repeattrack" />
@@ -46,7 +46,7 @@
             <ColumnDefinition Width="Auto"/>
             <ColumnDefinition Width="Auto"/>
           </Grid.ColumnDefinitions>
           </Grid.ColumnDefinitions>
           <Border Name="TrackBackground" Grid.Column="1" Width="4" Margin="0,6" HorizontalAlignment="Center"/>
           <Border Name="TrackBackground" Grid.Column="1" Width="4" Margin="0,6" HorizontalAlignment="Center"/>
-          <Track Name="PART_Track" Grid.Column="1" Orientation="Vertical">
+          <Track Name="PART_Track" Grid.Column="1" IsDirectionReversed="{TemplateBinding IsDirectionReversed}" Orientation="Vertical">
             <Track.DecreaseButton>
             <Track.DecreaseButton>
                <RepeatButton Name="PART_DecreaseButton"
                <RepeatButton Name="PART_DecreaseButton"
                              Classes="repeattrack" />
                              Classes="repeattrack" />
@@ -80,6 +80,7 @@
   </Style>
   </Style>
   <Style Selector="Slider /template/ RepeatButton.repeattrack">
   <Style Selector="Slider /template/ RepeatButton.repeattrack">
     <Setter Property="Background" Value="Transparent"/>
     <Setter Property="Background" Value="Transparent"/>
+    <Setter Property="Focusable" Value="False"/>
     <Setter Property="Foreground" Value="{DynamicResource ThemeBorderLowBrush}"/>
     <Setter Property="Foreground" Value="{DynamicResource ThemeBorderLowBrush}"/>
     <Setter Property="Template">
     <Setter Property="Template">
         <ControlTemplate>
         <ControlTemplate>

+ 6 - 6
src/Avalonia.Themes.Fluent/Controls/Slider.xaml

@@ -62,9 +62,9 @@
                   <TickBar Name="TopTickBar" Placement="Top" Height="{DynamicResource SliderOutsideTickBarThemeHeight}" VerticalAlignment="Bottom" Margin="0,0,0,4" Grid.ColumnSpan="3" />
                   <TickBar Name="TopTickBar" Placement="Top" Height="{DynamicResource SliderOutsideTickBarThemeHeight}" VerticalAlignment="Bottom" Margin="0,0,0,4" Grid.ColumnSpan="3" />
                   <!-- <TickBar Name="HorizontalInlineTickBar" Placement="Top" Fill="{DynamicResource SliderInlineTickBarFill}" Height="{DynamicResource SliderTrackThemeHeight}" Grid.Row="1" Grid.ColumnSpan="3" /> -->
                   <!-- <TickBar Name="HorizontalInlineTickBar" Placement="Top" Fill="{DynamicResource SliderInlineTickBarFill}" Height="{DynamicResource SliderTrackThemeHeight}" Grid.Row="1" Grid.ColumnSpan="3" /> -->
                   <TickBar Name="BottomTickBar" Placement="Bottom" Height="{DynamicResource SliderOutsideTickBarThemeHeight}" VerticalAlignment="Top" Margin="0,4,0,0" Grid.Row="2" Grid.ColumnSpan="3" />
                   <TickBar Name="BottomTickBar" Placement="Bottom" Height="{DynamicResource SliderOutsideTickBarThemeHeight}" VerticalAlignment="Top" Margin="0,4,0,0" Grid.Row="2" Grid.ColumnSpan="3" />
-                  <Track Name="PART_Track" Grid.Row="1" Grid.ColumnSpan="3" Orientation="Horizontal">
+                  <Track Name="PART_Track" Grid.Row="1" Grid.ColumnSpan="3" IsDirectionReversed="{TemplateBinding IsDirectionReversed}" Orientation="Horizontal">
                     <Track.DecreaseButton>
                     <Track.DecreaseButton>
-                      <RepeatButton Name="PART_DecreaseButton" Background="{TemplateBinding Foreground}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
+                      <RepeatButton Name="PART_DecreaseButton" Background="{TemplateBinding Foreground}" Focusable="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
                         <RepeatButton.Template>
                         <RepeatButton.Template>
                           <ControlTemplate>
                           <ControlTemplate>
                             <Grid>
                             <Grid>
@@ -76,7 +76,7 @@
                       </RepeatButton>
                       </RepeatButton>
                     </Track.DecreaseButton>
                     </Track.DecreaseButton>
                     <Track.IncreaseButton>
                     <Track.IncreaseButton>
-                      <RepeatButton Name="PART_IncreaseButton" Background="{TemplateBinding Background}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
+                      <RepeatButton Name="PART_IncreaseButton" Background="{TemplateBinding Background}" Focusable="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
                         <RepeatButton.Template>
                         <RepeatButton.Template>
                           <ControlTemplate>
                           <ControlTemplate>
                             <Grid>
                             <Grid>
@@ -124,9 +124,9 @@
                   <TickBar Name="LeftTickBar" Placement="Left" Width="{DynamicResource SliderOutsideTickBarThemeHeight}" HorizontalAlignment="Right" Margin="0,0,4,0" Grid.RowSpan="3" />
                   <TickBar Name="LeftTickBar" Placement="Left" Width="{DynamicResource SliderOutsideTickBarThemeHeight}" HorizontalAlignment="Right" Margin="0,0,4,0" Grid.RowSpan="3" />
                   <!-- <TickBar Name="VerticalInlineTickBar" Placement="Inline" Fill="{DynamicResource SliderInlineTickBarFill}" Width="{DynamicResource SliderTrackThemeHeight}" Grid.Column="1" Grid.RowSpan="3" /> -->
                   <!-- <TickBar Name="VerticalInlineTickBar" Placement="Inline" Fill="{DynamicResource SliderInlineTickBarFill}" Width="{DynamicResource SliderTrackThemeHeight}" Grid.Column="1" Grid.RowSpan="3" /> -->
                   <TickBar Name="RightTickBar" Placement="Right" Width="{DynamicResource SliderOutsideTickBarThemeHeight}" HorizontalAlignment="Left" Margin="4,0,0,0" Grid.Column="2" Grid.RowSpan="3" />
                   <TickBar Name="RightTickBar" Placement="Right" Width="{DynamicResource SliderOutsideTickBarThemeHeight}" HorizontalAlignment="Left" Margin="4,0,0,0" Grid.Column="2" Grid.RowSpan="3" />
-                  <Track Name="PART_Track" Grid.Column="1" Grid.ColumnSpan="1" Grid.RowSpan="3" Orientation="Vertical">
+                  <Track Name="PART_Track" Grid.Column="1" Grid.ColumnSpan="1" Grid.RowSpan="3" IsDirectionReversed="{TemplateBinding IsDirectionReversed}" Orientation="Vertical">
                     <Track.DecreaseButton>
                     <Track.DecreaseButton>
-                      <RepeatButton Name="PART_DecreaseButton" Background="{TemplateBinding Foreground}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
+                      <RepeatButton Name="PART_DecreaseButton" Background="{TemplateBinding Foreground}" Focusable="False" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
                         <RepeatButton.Template>
                         <RepeatButton.Template>
                           <ControlTemplate>
                           <ControlTemplate>
                             <Grid>
                             <Grid>
@@ -138,7 +138,7 @@
                       </RepeatButton>
                       </RepeatButton>
                     </Track.DecreaseButton>
                     </Track.DecreaseButton>
                     <Track.IncreaseButton>
                     <Track.IncreaseButton>
-                      <RepeatButton Name="PART_IncreaseButton" Background="{TemplateBinding Background}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
+                      <RepeatButton Name="PART_IncreaseButton" Background="{TemplateBinding Background}" Focusable="False" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
                         <RepeatButton.Template>
                         <RepeatButton.Template>
                           <ControlTemplate>
                           <ControlTemplate>
                             <Grid>
                             <Grid>

+ 2 - 2
src/Avalonia.Visuals/Media/FormattedText.cs

@@ -36,7 +36,7 @@ namespace Avalonia.Media
         }
         }
 
 
         /// <summary>
         /// <summary>
-        /// 
+        /// Initializes a new instance of the <see cref="FormattedText"/> class.
         /// </summary>
         /// </summary>
         /// <param name="text"></param>
         /// <param name="text"></param>
         /// <param name="typeface"></param>
         /// <param name="typeface"></param>
@@ -45,7 +45,7 @@ namespace Avalonia.Media
         /// <param name="textWrapping"></param>
         /// <param name="textWrapping"></param>
         /// <param name="constraint"></param>
         /// <param name="constraint"></param>
         public FormattedText(string text, Typeface typeface, double fontSize, TextAlignment textAlignment,
         public FormattedText(string text, Typeface typeface, double fontSize, TextAlignment textAlignment,
-            TextWrapping textWrapping, Size constraint)
+            TextWrapping textWrapping, Size constraint) : this()
         {
         {
             _text = text;
             _text = text;
 
 

+ 18 - 0
src/Avalonia.Visuals/Media/PathGeometryCollections.cs

@@ -1,9 +1,27 @@
 using Avalonia.Collections;
 using Avalonia.Collections;
+using Avalonia.Visuals.Platform;
 
 
 namespace Avalonia.Media
 namespace Avalonia.Media
 {
 {
     public sealed class PathFigures : AvaloniaList<PathFigure>
     public sealed class PathFigures : AvaloniaList<PathFigure>
     {
     {
+        /// <summary>
+        /// Parses the specified path data to a <see cref="PathFigures"/>.
+        /// </summary>
+        /// <param name="pathData">The s.</param>
+        /// <returns></returns>
+        public static PathFigures Parse(string pathData)
+        {
+            var pathGeometry = new PathGeometry();
+            
+            using (var context = new PathGeometryContext(pathGeometry))
+            using (var parser = new PathMarkupParser(context))
+            {
+                parser.Parse(pathData);
+            }
+
+            return pathGeometry.Figures;
+        }
     }
     }
 
 
     public sealed class PathSegments : AvaloniaList<PathSegment>
     public sealed class PathSegments : AvaloniaList<PathSegment>

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

@@ -958,7 +958,7 @@ namespace Avalonia.Win32
                 MaximizeWithoutCoveringTaskbar();
                 MaximizeWithoutCoveringTaskbar();
             }
             }
 
 
-            if (!Design.IsDesignMode)
+            if (!Design.IsDesignMode && activate)
             {
             {
                 SetFocus(_hwnd);
                 SetFocus(_hwnd);
             }
             }

+ 1 - 0
tests/Avalonia.Controls.UnitTests/TabControlTests.cs

@@ -374,6 +374,7 @@ namespace Avalonia.Controls.UnitTests
                     new TextBlock { Tag = "bar", Text = x }),
                     new TextBlock { Tag = "bar", Text = x }),
                 Items = new[] { "Foo" },
                 Items = new[] { "Foo" },
             };
             };
+            var root = new TestRoot(target);
 
 
             ApplyTemplate(target);
             ApplyTemplate(target);
             ((ContentPresenter)target.ContentPart).UpdateChild();
             ((ContentPresenter)target.ContentPart).UpdateChild();

+ 37 - 1
tests/Avalonia.LeakTests/ControlTests.cs

@@ -313,7 +313,6 @@ namespace Avalonia.LeakTests
             }
             }
         }
         }
 
 
-
         [Fact]
         [Fact]
         public void Slider_Is_Freed()
         public void Slider_Is_Freed()
         {
         {
@@ -347,6 +346,43 @@ namespace Avalonia.LeakTests
             }
             }
         }
         }
 
 
+        [Fact]
+        public void TabItem_Is_Freed()
+        {
+            using (Start())
+            {
+                Func<Window> run = () =>
+                {
+                    var window = new Window
+                    {
+                        Content = new TabControl
+                        {
+                            Items = new[] { new TabItem() }
+                        }
+                    };
+
+                    window.Show();
+
+                    // Do a layout and make sure that TabControl and TabItem gets added to visual tree.
+                    window.LayoutManager.ExecuteInitialLayoutPass();
+                    var tabControl = Assert.IsType<TabControl>(window.Presenter.Child);
+                    Assert.IsType<TabItem>(tabControl.Presenter.Panel.Children[0]);
+
+                    // Clear the items and ensure the TabItem is removed.
+                    tabControl.Items = null;
+                    window.LayoutManager.ExecuteLayoutPass();
+                    Assert.Empty(tabControl.Presenter.Panel.Children);
+
+                    return window;
+                };
+
+                var result = run();
+
+                dotMemory.Check(memory =>
+                    Assert.Equal(0, memory.GetObjects(where => where.Type.Is<TabItem>()).ObjectsCount));
+            }
+        }
+
         [Fact]
         [Fact]
         public void RendererIsDisposed()
         public void RendererIsDisposed()
         {
         {