From cbbe8f77ec7ce17d4ee07265780af13f9dd348f3 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Sun, 12 Dec 2021 20:47:37 -0500 Subject: [PATCH] Implement HamburgerMenu control to be used in repo samples --- Avalonia.sln | 29 +- samples/ControlCatalog/App.xaml | 2 +- samples/ControlCatalog/ControlCatalog.csproj | 1 + samples/ControlCatalog/MainView.xaml | 262 ++++++++++++------ samples/ControlCatalog/MainView.xaml.cs | 22 +- samples/ControlCatalog/MainWindow.xaml | 12 +- samples/ControlCatalog/MainWindow.xaml.cs | 26 -- samples/ControlCatalog/SideBar.xaml | 84 ------ samples/RenderDemo/App.xaml | 15 +- samples/RenderDemo/MainWindow.xaml | 121 ++++---- samples/RenderDemo/RenderDemo.csproj | 1 + samples/RenderDemo/SideBar.xaml | 67 ----- samples/SampleControls/ControlSamples.csproj | 23 ++ .../HamburgerMenu/HamburgerMenu.cs | 77 +++++ .../HamburgerMenu/HamburgerMenu.xaml | 242 ++++++++++++++++ 15 files changed, 634 insertions(+), 350 deletions(-) delete mode 100644 samples/ControlCatalog/SideBar.xaml delete mode 100644 samples/RenderDemo/SideBar.xaml create mode 100644 samples/SampleControls/ControlSamples.csproj create mode 100644 samples/SampleControls/HamburgerMenu/HamburgerMenu.cs create mode 100644 samples/SampleControls/HamburgerMenu/HamburgerMenu.xaml diff --git a/Avalonia.sln b/Avalonia.sln index a5707d086f..a288bacbde 100644 --- a/Avalonia.sln +++ b/Avalonia.sln @@ -234,7 +234,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Web.Blazor", "src\ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.Web", "samples\ControlCatalog.Web\ControlCatalog.Web.csproj", "{C08E9894-AA92-426E-BF56-033E262CAD3E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsInteropTest", "samples\interop\WindowsInteropTest\WindowsInteropTest.csproj", "{26A98DA1-D89D-4A95-8152-349F404DA2E2}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WindowsInteropTest", "samples\interop\WindowsInteropTest\WindowsInteropTest.csproj", "{26A98DA1-D89D-4A95-8152-349F404DA2E2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlSamples", "samples\SampleControls\ControlSamples.csproj", "{A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}" EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution @@ -2170,6 +2172,30 @@ Global {26A98DA1-D89D-4A95-8152-349F404DA2E2}.Release|iPhone.Build.0 = Release|Any CPU {26A98DA1-D89D-4A95-8152-349F404DA2E2}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {26A98DA1-D89D-4A95-8152-349F404DA2E2}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.AppStore|iPhone.Build.0 = Debug|Any CPU + {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Debug|iPhone.Build.0 = Debug|Any CPU + {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Release|Any CPU.Build.0 = Release|Any CPU + {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Release|iPhone.ActiveCfg = Release|Any CPU + {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Release|iPhone.Build.0 = Release|Any CPU + {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Release|iPhoneSimulator.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2233,6 +2259,7 @@ Global {25831348-EB2A-483E-9576-E8F6528674A5} = {86A3F706-DC3C-43C6-BE1B-B98F5BAAA268} {C08E9894-AA92-426E-BF56-033E262CAD3E} = {9B9E3891-2366-4253-A952-D08BCEB71098} {26A98DA1-D89D-4A95-8152-349F404DA2E2} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9} + {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270} = {9B9E3891-2366-4253-A952-D08BCEB71098} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A} diff --git a/samples/ControlCatalog/App.xaml b/samples/ControlCatalog/App.xaml index 7ae7b4d3bb..227b31bf20 100644 --- a/samples/ControlCatalog/App.xaml +++ b/samples/ControlCatalog/App.xaml @@ -28,7 +28,7 @@ - + diff --git a/samples/ControlCatalog/ControlCatalog.csproj b/samples/ControlCatalog/ControlCatalog.csproj index 53ad213d92..7864459e77 100644 --- a/samples/ControlCatalog/ControlCatalog.csproj +++ b/samples/ControlCatalog/ControlCatalog.csproj @@ -26,6 +26,7 @@ + diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml index f61b59e6cd..2ae944e6d4 100644 --- a/samples/ControlCatalog/MainView.xaml +++ b/samples/ControlCatalog/MainView.xaml @@ -1,108 +1,190 @@ - + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - + + - - + + + + + - + - - - + + + + + + + + - + ScrollViewer.HorizontalScrollBarVisibility="Disabled" + ScrollViewer.VerticalScrollBarVisibility="Disabled"> + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - No Decorations - Border Only - Full Decorations - - - Fluent - Light - Fluent - Dark - Simple - Light - Simple - Dark - - - None - Transparent - Blur - AcrylicBlur - Mica - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + No Decorations + Border Only + Full Decorations + + + Fluent - Light + Fluent - Dark + Simple - Light + Simple - Dark + + + + None + Transparent + Blur + AcrylicBlur + Mica + + + + + + + diff --git a/samples/ControlCatalog/MainView.xaml.cs b/samples/ControlCatalog/MainView.xaml.cs index c84f2f06b6..163547ac4d 100644 --- a/samples/ControlCatalog/MainView.xaml.cs +++ b/samples/ControlCatalog/MainView.xaml.cs @@ -6,6 +6,8 @@ using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml.MarkupExtensions; using Avalonia.Markup.Xaml.Styling; using Avalonia.Markup.Xaml.XamlIl; +using Avalonia.Media; +using Avalonia.Media.Immutable; using Avalonia.Platform; using ControlCatalog.Pages; @@ -16,9 +18,12 @@ namespace ControlCatalog public MainView() { AvaloniaXamlLoader.Load(this); + + var sideBar = this.FindControl("Sidebar"); + if (AvaloniaLocator.Current.GetService().GetRuntimeInfo().IsDesktop) { - IList tabItems = ((IList)this.FindControl("Sidebar").Items); + IList tabItems = ((IList)sideBar.Items); tabItems.Add(new TabItem() { Header = "Dialogs", @@ -58,6 +63,21 @@ namespace ControlCatalog if (VisualRoot is Window window) window.SystemDecorations = (SystemDecorations)decorations.SelectedIndex; }; + + var transparencyLevels = this.Find("TransparencyLevels"); + IDisposable backgroundSetter = null, paneBackgroundSetter = null; + transparencyLevels.SelectionChanged += (sender, e) => + { + backgroundSetter?.Dispose(); + paneBackgroundSetter?.Dispose(); + if (transparencyLevels.SelectedItem is WindowTransparencyLevel selected + && selected != WindowTransparencyLevel.None) + { + var semiTransparentBrush = new ImmutableSolidColorBrush(Colors.Gray, 0.5); + backgroundSetter = sideBar.SetValue(BackgroundProperty, semiTransparentBrush, Avalonia.Data.BindingPriority.Style); + paneBackgroundSetter = sideBar.SetValue(SplitView.PaneBackgroundProperty, semiTransparentBrush, Avalonia.Data.BindingPriority.Style); + } + }; } protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) diff --git a/samples/ControlCatalog/MainWindow.xaml b/samples/ControlCatalog/MainWindow.xaml index 375345f64e..1e4bf2de38 100644 --- a/samples/ControlCatalog/MainWindow.xaml +++ b/samples/ControlCatalog/MainWindow.xaml @@ -61,17 +61,7 @@ - - - - - - - - - - - + diff --git a/samples/ControlCatalog/MainWindow.xaml.cs b/samples/ControlCatalog/MainWindow.xaml.cs index a9900471c5..dd62698cc7 100644 --- a/samples/ControlCatalog/MainWindow.xaml.cs +++ b/samples/ControlCatalog/MainWindow.xaml.cs @@ -33,9 +33,6 @@ namespace ControlCatalog DataContext = new MainWindowViewModel(_notificationArea); _recentMenu = ((NativeMenu.GetMenu(this).Items[0] as NativeMenuItem).Menu.Items[2] as NativeMenuItem).Menu; - var mainMenu = this.FindControl("MainMenu"); - mainMenu.AttachedToVisualTree += MenuAttached; - ExtendClientAreaChromeHints = Avalonia.Platform.ExtendClientAreaChromeHints.OSXThickTitleBar; } @@ -45,14 +42,6 @@ namespace ControlCatalog new KeyGesture(Key.Q, KeyModifiers.Meta) : new KeyGesture(Key.F4, KeyModifiers.Alt); - public void MenuAttached(object sender, VisualTreeAttachmentEventArgs e) - { - if (NativeMenu.GetIsNativeMenuExported(this) && sender is Menu mainMenu) - { - mainMenu.IsVisible = false; - } - } - public void OnOpenClicked(object sender, EventArgs args) { _recentMenu.Items.Insert(0, new NativeMenuItem("Item " + (_recentMenu.Items.Count + 1))); @@ -65,21 +54,6 @@ namespace ControlCatalog private void InitializeComponent() { - // TODO: iOS does not support dynamically loading assemblies - // so we must refer to this resource DLL statically. For - // now I am doing that here. But we need a better solution!! - // Note, theme swiching probably will not work in runtime for iOS. - if (Application.Current.Styles.Contains(App.FluentDark) - || Application.Current.Styles.Contains(App.FluentLight)) - { - var theme = new Avalonia.Themes.Fluent.Controls.FluentControls(); - theme.TryGetResource("Button", out _); - } - else - { - var theme = new Avalonia.Themes.Default.DefaultTheme(); - theme.TryGetResource("Button", out _); - } AvaloniaXamlLoader.Load(this); } } diff --git a/samples/ControlCatalog/SideBar.xaml b/samples/ControlCatalog/SideBar.xaml deleted file mode 100644 index 2b5215a3fe..0000000000 --- a/samples/ControlCatalog/SideBar.xaml +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/samples/RenderDemo/App.xaml b/samples/RenderDemo/App.xaml index 7cdcea2e1d..66d97a6444 100644 --- a/samples/RenderDemo/App.xaml +++ b/samples/RenderDemo/App.xaml @@ -1,9 +1,8 @@ - - - - - + + + + + diff --git a/samples/RenderDemo/MainWindow.xaml b/samples/RenderDemo/MainWindow.xaml index f37df56b73..a4c6299278 100644 --- a/samples/RenderDemo/MainWindow.xaml +++ b/samples/RenderDemo/MainWindow.xaml @@ -1,68 +1,67 @@ - - - - - - - - + + + + + + + + + + + + + + - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/RenderDemo/RenderDemo.csproj b/samples/RenderDemo/RenderDemo.csproj index eed6fa9e89..54d5ca4b3b 100644 --- a/samples/RenderDemo/RenderDemo.csproj +++ b/samples/RenderDemo/RenderDemo.csproj @@ -10,6 +10,7 @@ + diff --git a/samples/RenderDemo/SideBar.xaml b/samples/RenderDemo/SideBar.xaml deleted file mode 100644 index b82a7b0514..0000000000 --- a/samples/RenderDemo/SideBar.xaml +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - - - - diff --git a/samples/SampleControls/ControlSamples.csproj b/samples/SampleControls/ControlSamples.csproj new file mode 100644 index 0000000000..6eaf11a0fc --- /dev/null +++ b/samples/SampleControls/ControlSamples.csproj @@ -0,0 +1,23 @@ + + + + netstandard2.0 + enable + + + + + %(Filename) + + + Designer + + + + + + + + + + diff --git a/samples/SampleControls/HamburgerMenu/HamburgerMenu.cs b/samples/SampleControls/HamburgerMenu/HamburgerMenu.cs new file mode 100644 index 0000000000..bbfd3d87ca --- /dev/null +++ b/samples/SampleControls/HamburgerMenu/HamburgerMenu.cs @@ -0,0 +1,77 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.Primitives; +using Avalonia.Media; + +namespace ControlSamples +{ + public class HamburgerMenu : TabControl + { + private SplitView? _splitView; + + public static readonly StyledProperty PaneBackgroundProperty = + SplitView.PaneBackgroundProperty.AddOwner(); + + public IBrush? PaneBackground + { + get => GetValue(PaneBackgroundProperty); + set => SetValue(PaneBackgroundProperty, value); + } + + public static readonly StyledProperty ContentBackgroundProperty = + AvaloniaProperty.Register(nameof(ContentBackground)); + + public IBrush? ContentBackground + { + get => GetValue(ContentBackgroundProperty); + set => SetValue(ContentBackgroundProperty, value); + } + + public static readonly StyledProperty ExpandedModeThresholdWidthProperty = + AvaloniaProperty.Register(nameof(ExpandedModeThresholdWidth), 1008); + + public int ExpandedModeThresholdWidth + { + get => GetValue(ExpandedModeThresholdWidthProperty); + set => SetValue(ExpandedModeThresholdWidthProperty, value); + } + + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) + { + base.OnApplyTemplate(e); + + _splitView = e.NameScope.Find("PART_NavigationPane"); + } + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + + if (change.Property == BoundsProperty && _splitView is not null) + { + var oldBounds = change.OldValue.GetValueOrDefault(); + var newBounds = change.NewValue.GetValueOrDefault(); + EnsureSplitViewMode(oldBounds, newBounds); + } + } + + private void EnsureSplitViewMode(Rect oldBounds, Rect newBounds) + { + if (_splitView is not null) + { + var threshold = ExpandedModeThresholdWidth; + + if (newBounds.Width >= threshold && oldBounds.Width < threshold) + { + _splitView.DisplayMode = SplitViewDisplayMode.Inline; + _splitView.IsPaneOpen = true; + } + else if (newBounds.Width < threshold && oldBounds.Width >= threshold) + { + _splitView.DisplayMode = SplitViewDisplayMode.Overlay; + _splitView.IsPaneOpen = false; + } + } + } + } +} diff --git a/samples/SampleControls/HamburgerMenu/HamburgerMenu.xaml b/samples/SampleControls/HamburgerMenu/HamburgerMenu.xaml new file mode 100644 index 0000000000..1aa7f8ea04 --- /dev/null +++ b/samples/SampleControls/HamburgerMenu/HamburgerMenu.xaml @@ -0,0 +1,242 @@ + + + + + + + + + + + + + + + + + + + + + 40 + 200 + 36 + 36 + 32 + 12,0,0,0 + 52,0,0,0 + 212,0,0,0 + 1 1 1 1 #2000, 0 0 1 1 #2fff + 0 0 1 1 #2000 + + + + + + + + + + + + + + + + + + + + + + + +