diff --git a/native/Avalonia.Native/src/OSX/common.h b/native/Avalonia.Native/src/OSX/common.h index ea48a19874..05b2d762ae 100644 --- a/native/Avalonia.Native/src/OSX/common.h +++ b/native/Avalonia.Native/src/OSX/common.h @@ -28,6 +28,8 @@ extern IAvnNativeControlHost* CreateNativeControlHost(NSView* parent); extern void SetAppMenu (NSString* appName, IAvnMenu* appMenu); extern IAvnMenu* GetAppMenu (); extern NSMenuItem* GetAppMenuItem (); +extern void SetAutoGenerateDefaultAppMenuItems (bool enabled); +extern bool GetAutoGenerateDefaultAppMenuItems (); extern void InitializeAvnApp(); extern NSApplicationActivationPolicy AvnDesiredActivationPolicy; diff --git a/native/Avalonia.Native/src/OSX/main.mm b/native/Avalonia.Native/src/OSX/main.mm index 72f5aa0a7d..17746e1d1d 100644 --- a/native/Avalonia.Native/src/OSX/main.mm +++ b/native/Avalonia.Native/src/OSX/main.mm @@ -2,6 +2,7 @@ #define COM_GUIDS_MATERIALIZE #include "common.h" +static bool s_generateDefaultAppMenuItems = true; static NSString* s_appTitle = @"Avalonia"; // Copyright (c) 2011 The Chromium Authors. All rights reserved. @@ -122,6 +123,12 @@ public: ? NSApplicationActivationPolicyRegular : NSApplicationActivationPolicyAccessory; return S_OK; } + + virtual HRESULT SetDisableDefaultApplicationMenuItems (bool enabled) override + { + SetAutoGenerateDefaultAppMenuItems(!enabled); + return S_OK; + } }; /// See "Using POSIX Threads in a Cocoa Application" section here: @@ -310,3 +317,13 @@ CGFloat PrimaryDisplayHeight() { return NSMaxY([[[NSScreen screens] firstObject] frame]); } + +void SetAutoGenerateDefaultAppMenuItems (bool enabled) +{ + s_generateDefaultAppMenuItems = enabled; +} + +bool GetAutoGenerateDefaultAppMenuItems () +{ + return s_generateDefaultAppMenuItems; +} diff --git a/native/Avalonia.Native/src/OSX/menu.mm b/native/Avalonia.Native/src/OSX/menu.mm index 198b01714f..ea5cca9ce8 100644 --- a/native/Avalonia.Native/src/OSX/menu.mm +++ b/native/Avalonia.Native/src/OSX/menu.mm @@ -445,47 +445,50 @@ extern void SetAppMenu (NSString* appName, IAvnMenu* menu) 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 { diff --git a/samples/ControlCatalog/Pages/AcrylicPage.xaml b/samples/ControlCatalog/Pages/AcrylicPage.xaml index 96cfcc5288..7635e1ccc3 100644 --- a/samples/ControlCatalog/Pages/AcrylicPage.xaml +++ b/samples/ControlCatalog/Pages/AcrylicPage.xaml @@ -16,13 +16,13 @@ - - + + - - + + diff --git a/samples/ControlCatalog/Pages/SliderPage.xaml b/samples/ControlCatalog/Pages/SliderPage.xaml index eeb198976b..b4901ec780 100644 --- a/samples/ControlCatalog/Pages/SliderPage.xaml +++ b/samples/ControlCatalog/Pages/SliderPage.xaml @@ -45,6 +45,12 @@ + + diff --git a/src/Avalonia.Animation/Animation.cs b/src/Avalonia.Animation/Animation.cs index ca1d97290e..05142532e9 100644 --- a/src/Avalonia.Animation/Animation.cs +++ b/src/Avalonia.Animation/Animation.cs @@ -22,7 +22,7 @@ namespace Avalonia.Animation /// public static readonly DirectProperty DurationProperty = AvaloniaProperty.RegisterDirect( - nameof(_duration), + nameof(Duration), o => o._duration, (o, v) => o._duration = v); @@ -31,7 +31,7 @@ namespace Avalonia.Animation /// public static readonly DirectProperty IterationCountProperty = AvaloniaProperty.RegisterDirect( - nameof(_iterationCount), + nameof(IterationCount), o => o._iterationCount, (o, v) => o._iterationCount = v); @@ -40,7 +40,7 @@ namespace Avalonia.Animation /// public static readonly DirectProperty PlaybackDirectionProperty = AvaloniaProperty.RegisterDirect( - nameof(_playbackDirection), + nameof(PlaybackDirection), o => o._playbackDirection, (o, v) => o._playbackDirection = v); @@ -49,7 +49,7 @@ namespace Avalonia.Animation /// public static readonly DirectProperty FillModeProperty = AvaloniaProperty.RegisterDirect( - nameof(_fillMode), + nameof(FillMode), o => o._fillMode, (o, v) => o._fillMode = v); @@ -58,7 +58,7 @@ namespace Avalonia.Animation /// public static readonly DirectProperty EasingProperty = AvaloniaProperty.RegisterDirect( - nameof(_easing), + nameof(Easing), o => o._easing, (o, v) => o._easing = v); @@ -67,7 +67,7 @@ namespace Avalonia.Animation /// public static readonly DirectProperty DelayProperty = AvaloniaProperty.RegisterDirect( - nameof(_delay), + nameof(Delay), o => o._delay, (o, v) => o._delay = v); @@ -76,7 +76,7 @@ namespace Avalonia.Animation /// public static readonly DirectProperty DelayBetweenIterationsProperty = AvaloniaProperty.RegisterDirect( - nameof(_delayBetweenIterations), + nameof(DelayBetweenIterations), o => o._delayBetweenIterations, (o, v) => o._delayBetweenIterations = v); @@ -85,7 +85,7 @@ namespace Avalonia.Animation /// public static readonly DirectProperty SpeedRatioProperty = AvaloniaProperty.RegisterDirect( - nameof(_speedRatio), + nameof(SpeedRatio), o => o._speedRatio, (o, v) => o._speedRatio = v, defaultBindingMode: BindingMode.TwoWay); diff --git a/src/Avalonia.Controls.DataGrid/DataGridTemplateColumn.cs b/src/Avalonia.Controls.DataGrid/DataGridTemplateColumn.cs index e513a7b678..7e95dd100c 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridTemplateColumn.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridTemplateColumn.cs @@ -8,6 +8,7 @@ using Avalonia.Controls.Utils; using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.Media; +using Avalonia.Metadata; using Avalonia.Utilities; namespace Avalonia.Controls @@ -22,6 +23,7 @@ namespace Avalonia.Controls o => o.CellTemplate, (o, v) => o.CellTemplate = v); + [Content] public IDataTemplate CellTemplate { get { return _cellTemplate; } diff --git a/src/Avalonia.Controls/Generators/TabItemContainerGenerator.cs b/src/Avalonia.Controls/Generators/TabItemContainerGenerator.cs index d2e05ee136..840a1f66f1 100644 --- a/src/Avalonia.Controls/Generators/TabItemContainerGenerator.cs +++ b/src/Avalonia.Controls/Generators/TabItemContainerGenerator.cs @@ -1,4 +1,10 @@ +using System; +using System.Collections.Generic; using Avalonia.Controls.Primitives; +using Avalonia.Controls.Templates; +using Avalonia.LogicalTree; +using Avalonia.Reactive; +using Avalonia.VisualTree; namespace Avalonia.Controls.Generators { @@ -16,11 +22,15 @@ namespace Avalonia.Controls.Generators { var tabItem = (TabItem)base.CreateContainer(item); - tabItem[~TabControl.TabStripPlacementProperty] = Owner[~TabControl.TabStripPlacementProperty]; + tabItem.Bind(TabItem.TabStripPlacementProperty, new OwnerBinding( + tabItem, + TabControl.TabStripPlacementProperty)); if (tabItem.HeaderTemplate == null) { - tabItem[~HeaderedContentControl.HeaderTemplateProperty] = Owner[~ItemsControl.ItemTemplateProperty]; + tabItem.Bind(TabItem.HeaderTemplateProperty, new OwnerBinding( + tabItem, + TabControl.ItemTemplateProperty)); } if (tabItem.Header == null) @@ -40,10 +50,49 @@ namespace Avalonia.Controls.Generators if (!(tabItem.Content is IControl)) { - tabItem[~ContentControl.ContentTemplateProperty] = Owner[~TabControl.ContentTemplateProperty]; + tabItem.Bind(TabItem.ContentTemplateProperty, new OwnerBinding( + tabItem, + TabControl.ContentTemplateProperty)); } return tabItem; } + + private class OwnerBinding : SingleSubscriberObservableBase + { + private readonly TabItem _item; + private readonly StyledProperty _ownerProperty; + private IDisposable _ownerSubscription; + private IDisposable _propertySubscription; + + public OwnerBinding(TabItem item, StyledProperty 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)); + } + } + } } } diff --git a/src/Avalonia.Controls/NativeControlHost.cs b/src/Avalonia.Controls/NativeControlHost.cs index 20eac11c2c..64414b1f47 100644 --- a/src/Avalonia.Controls/NativeControlHost.cs +++ b/src/Avalonia.Controls/NativeControlHost.cs @@ -157,10 +157,14 @@ namespace Avalonia.Controls var needsShow = IsEffectivelyVisible && bounds.HasValue; if (needsShow) + { + if (bounds.Value.IsEmpty) + return false; _attachment?.ShowInBounds(bounds.Value); + } else _attachment?.HideWithSize(Bounds.Size); - return false; + return true; } private void CheckDestruction() diff --git a/src/Avalonia.Controls/Slider.cs b/src/Avalonia.Controls/Slider.cs index 74de33529a..e02efc2bd2 100644 --- a/src/Avalonia.Controls/Slider.cs +++ b/src/Avalonia.Controls/Slider.cs @@ -49,6 +49,12 @@ namespace Avalonia.Controls public static readonly StyledProperty OrientationProperty = ScrollBar.OrientationProperty.AddOwner(); + /// + /// Defines the property. + /// + public static readonly StyledProperty IsDirectionReversedProperty = + Track.IsDirectionReversedProperty.AddOwner(); + /// /// Defines the property. /// @@ -83,7 +89,6 @@ namespace Avalonia.Controls private IDisposable _increaseButtonSubscription; private IDisposable _increaseButtonReleaseDispose; private IDisposable _pointerMovedDispose; - private IDisposable _trackOnKeyDownDispose; private const double Tolerance = 0.0001; @@ -93,6 +98,7 @@ namespace Avalonia.Controls static Slider() { PressedMixin.Attach(); + FocusableProperty.OverrideDefaultValue(true); OrientationProperty.OverrideDefaultValue(typeof(Slider), Orientation.Horizontal); Thumb.DragStartedEvent.AddClassHandler((x, e) => x.OnThumbDragStarted(e), RoutingStrategies.Bubble); Thumb.DragCompletedEvent.AddClassHandler((x, e) => x.OnThumbDragCompleted(e), @@ -127,6 +133,19 @@ namespace Avalonia.Controls set { SetValue(OrientationProperty, value); } } + /// + /// Gets or sets the direction of increasing 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. + /// + public bool IsDirectionReversed + { + get { return GetValue(IsDirectionReversedProperty); } + set { SetValue(IsDirectionReversedProperty, value); } + } + /// /// Gets or sets a value that indicates whether the automatically moves the to the closest tick mark. /// @@ -165,7 +184,6 @@ namespace Avalonia.Controls _increaseButtonSubscription?.Dispose(); _increaseButtonReleaseDispose?.Dispose(); _pointerMovedDispose?.Dispose(); - _trackOnKeyDownDispose?.Dispose(); _decreaseButton = e.NameScope.Find