diff --git a/samples/ControlCatalog/App.xaml b/samples/ControlCatalog/App.xaml index 336eae7553..06167404ea 100644 --- a/samples/ControlCatalog/App.xaml +++ b/samples/ControlCatalog/App.xaml @@ -8,8 +8,7 @@ - - + @@ -28,6 +27,9 @@ + M10 2.5a7.5 7.5 0 0 1 5.964 12.048l4.743 4.745a1 1 0 0 1-1.32 1.497l-.094-.083-4.745-4.743A7.5 7.5 0 1 1 10 2.5Zm0 2a5.5 5.5 0 1 0 0 11 5.5 5.5 0 0 0 0-11Z + M24 0C37.2548 0 48 10.7452 48 24V42C48 45.3137 45.3137 48 42 48H24C10.7452 48 0 37.2548 0 24C0 10.7452 10.7452 0 24 0ZM24 7C16.3489 7 9.87832 12.0545 7.74496 19.0065C10.3931 19.1342 12.5 21.321 12.5 24C12.5 26.6793 10.3926 28.8664 7.74496 28.9941C9.83517 35.8054 16.0901 40.7958 23.5395 40.9939C26.6226 40.9252 29.1092 40.2605 31 39V41H41V24C41 14.827 33.7348 7.35088 24.6446 7.012L24.323 7.00301L24 7ZM24 16C28.4183 16 32 19.5817 32 24C32 28.4183 28.4183 32 24 32C19.5817 32 16 28.4183 16 24C16 19.5817 19.5817 16 24 16ZM7.5 20.5C5.567 20.5 4 22.067 4 24C4 25.933 5.567 27.5 7.5 27.5C9.433 27.5 11 25.933 11 24C11 22.067 9.433 20.5 7.5 20.5Z + diff --git a/samples/ControlCatalog/Controls/HomeItemExpander.cs b/samples/ControlCatalog/Controls/HomeItemExpander.cs new file mode 100644 index 0000000000..e8443277d6 --- /dev/null +++ b/samples/ControlCatalog/Controls/HomeItemExpander.cs @@ -0,0 +1,103 @@ +using System.Windows.Input; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.Primitives; +using Avalonia.Data; + +namespace ControlCatalog.Controls +{ + public class HomeItemExpander : Expander, ISelectable + { + /// + /// Defines the property. + /// + public static readonly StyledProperty CommandProperty = + Button.CommandProperty.AddOwner(); + + /// + /// Defines the property. + /// + public static readonly StyledProperty CommandParameterProperty = + Button.CommandParameterProperty.AddOwner(); + + /// + /// Defines the property. + /// + public static readonly StyledProperty CanExpandProperty = + AvaloniaProperty.Register( + nameof(CanExpand), + defaultBindingMode: BindingMode.TwoWay); + + /// + /// Defines the property. + /// + public static readonly DirectProperty IsEffectivelyExpandedProperty = + AvaloniaProperty.RegisterDirect( + nameof(IsEffectivelyExpanded), + x => x.IsEffectivelyExpanded, + (x, o) => x.IsEffectivelyExpanded = o, + defaultBindingMode: BindingMode.TwoWay); + + /// + /// Defines the property. + /// + public static readonly StyledProperty IsSelectedProperty = + SelectingItemsControl.IsSelectedProperty.AddOwner(); + + /// + /// Gets or sets an to be invoked when the button is clicked. + /// + public ICommand? Command + { + get => GetValue(CommandProperty); + set => SetValue(CommandProperty, value); + } + + /// + /// Gets or sets a parameter to be passed to the . + /// + public object? CommandParameter + { + get => GetValue(CommandParameterProperty); + set => SetValue(CommandParameterProperty, value); + } + + /// + /// Gets or sets a value indicating whether the + /// content area is open and visible. + /// + public bool CanExpand + { + get => GetValue(CanExpandProperty); + set => SetValue(CanExpandProperty, value); + } + + /// + /// Gets or sets the selection state of the item. + /// + public bool IsSelected + { + get => GetValue(IsSelectedProperty); + set => SetValue(IsSelectedProperty, value); + } + + /// + /// Gets whether the is expanded + /// + public bool IsEffectivelyExpanded + { + get => field; + private set => SetAndRaise(IsEffectivelyExpandedProperty, ref field, value); + } + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + + if (change.Property == CanExpandProperty || change.Property == IsExpandedProperty) + { + IsEffectivelyExpanded = CanExpand && IsExpanded; + } + } + } +} diff --git a/samples/ControlCatalog/Controls/SectionControl.axaml b/samples/ControlCatalog/Controls/SectionControl.axaml new file mode 100644 index 0000000000..d5cd3fda04 --- /dev/null +++ b/samples/ControlCatalog/Controls/SectionControl.axaml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + diff --git a/samples/ControlCatalog/Controls/SectionControl.axaml.cs b/samples/ControlCatalog/Controls/SectionControl.axaml.cs new file mode 100644 index 0000000000..00b949a699 --- /dev/null +++ b/samples/ControlCatalog/Controls/SectionControl.axaml.cs @@ -0,0 +1,25 @@ +using System; +using Avalonia.Controls; +using Avalonia.Controls.Primitives; + +namespace ControlCatalog.Controls +{ + public partial class SectionControl : UserControl + { + public SectionControl() + { + InitializeComponent(); + } + + private void UniformGrid_OnSizeChanged(object? sender, SizeChangedEventArgs e) + { + if (sender is not UniformGrid grid) + return; + + const int minItemWidth = 248; + grid.Columns = Math.Max( + 1, + (int)((e.NewSize.Width + grid.ColumnSpacing) / (minItemWidth + grid.ColumnSpacing))); + } + } +} diff --git a/samples/ControlCatalog/Controls/SelectableButton.cs b/samples/ControlCatalog/Controls/SelectableButton.cs new file mode 100644 index 0000000000..ef54937e4c --- /dev/null +++ b/samples/ControlCatalog/Controls/SelectableButton.cs @@ -0,0 +1,79 @@ +using System; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.Metadata; +using Avalonia.Controls.Primitives; +using Avalonia.Data; +using Avalonia.Interactivity; + +namespace ControlCatalog.Controls +{ + [PseudoClasses(":selected")] + public class SelectableButton : ToggleButton, ISelectable + { + /// + /// Defines the property. + /// + public static readonly StyledProperty IsSelectedProperty = + AvaloniaProperty.Register(nameof(IsSelected), false, + defaultBindingMode: BindingMode.TwoWay); + + /// + /// Defines the event. + /// + public static readonly RoutedEvent IsSelectedChangedEvent = + RoutedEvent.Register( + nameof(IsSelectedChanged), + RoutingStrategies.Bubble); + + public SelectableButton() + { + UpdatePseudoClasses(IsSelected); + } + + /// + /// Gets or sets whether the is selected. + /// + public bool IsSelected + { + get => GetValue(IsSelectedProperty); + set => SetValue(IsSelectedProperty, value); + } + + /// + /// Raised when the property value changes. + /// + public event EventHandler? IsSelectedChanged + { + add => AddHandler(IsSelectedChangedEvent, value); + remove => RemoveHandler(IsSelectedChangedEvent, value); + } + + /// + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + + if (change.Property == IsSelectedProperty) + { + var newValue = change.GetNewValue(); + UpdatePseudoClasses(newValue); + OnIsSelectedChanged(new RoutedEventArgs(IsSelectedChangedEvent)); + } + } + + private void UpdatePseudoClasses(bool isSelected) + { + PseudoClasses.Set(":selected", isSelected); + } + + /// + /// Called when changes. + /// + /// Event arguments for the routed event that is raised by the default implementation of this method. + protected virtual void OnIsSelectedChanged(RoutedEventArgs e) + { + RaiseEvent(e); + } + } +} diff --git a/samples/ControlCatalog/CustomThemes.xaml b/samples/ControlCatalog/CustomThemes.xaml new file mode 100644 index 0000000000..0a2533acd5 --- /dev/null +++ b/samples/ControlCatalog/CustomThemes.xaml @@ -0,0 +1,359 @@ + + + + #99FFFFFF + #FF1F1F1F + #FF000000 + #FF171717 + + + + + + + + + #99000000 + #FFE6E6E6 + #FFFFFFFF + #FFF2F2F2 + + + + + + + + + + + + + + + + + + + + + + + + + + + 36 + 1 1 1 1 #2000, 0 0 1 1 #2fff + 8,0,4,0 + 2,0,0,0 + 12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/ControlCatalog/Icons.cs b/samples/ControlCatalog/Icons.cs index 5f99bdc877..8a1cdaf42f 100644 --- a/samples/ControlCatalog/Icons.cs +++ b/samples/ControlCatalog/Icons.cs @@ -193,5 +193,41 @@ namespace ControlCatalog // Home public const string Home = "M10,20V14H14V20H19V12H22L12,3L2,12H5V20H10Z"; + + // Desktop and Mobile + public const string DesktopMobile = "M8.255 9c.966 0 1.75.783 1.75 1.75v9.5A1.75 1.75 0 0 1 8.255 22H3.75A1.75 1.75 0 0 1 2 20.25v-9.5C2 9.783 2.784 9 3.75 9h4.505Zm0 1.5H3.75a.25.25 0 0 0-.25.25v9.5c0 .138.112.25.25.25h4.505a.25.25 0 0 0 .25-.25v-9.5a.25.25 0 0 0-.25-.25ZM6.25 18a.75.75 0 0 1 .102 1.493l-.102.007h-.5a.75.75 0 0 1-.102-1.493L5.75 18h.5Zm13.5-16a2.25 2.25 0 0 1 2.245 2.096L22 4.25v9a2.25 2.25 0 0 1-2.096 2.245l-.154.005h-3.746v2h1.246a.75.75 0 0 1 .102 1.493L17.25 19H11v-1.5h3.504v-2H11V14h8.75a.75.75 0 0 0 .743-.648l.007-.102v-9a.75.75 0 0 0-.75-.75H6.25a.75.75 0 0 0-.743.648L5.5 4.25V8H4V4.25a2.25 2.25 0 0 1 2.096-2.245L6.25 2h13.5Z"; + + // Keyboard float + public const string KeyboardFloat = "M21.25,19.5 C21.6642136,19.5 22,19.8357864 22,20.25 C22,20.6296958 21.7178461,20.943491 21.3517706,20.9931534 L21.25,21 L2.75,21 C2.33578644,21 2,20.6642136 2,20.25 C2,19.8703042 2.28215388,19.556509 2.64822944,19.5068466 L2.75,19.5 L21.25,19.5 Z M19.7453641,3 C20.9880048,3 21.9953641,4.00735931 21.9953641,5.25 L21.9953641,14.754591 C21.9953641,15.9972317 20.9880048,17.004591 19.7453641,17.004591 L13.2239763,17.0049687 C13.1062463,17.5730514 12.6029828,18 12,18 C11.3970172,18 10.8937537,17.5730514 10.7760237,17.0049687 L4.25,17.004591 C3.00735931,17.004591 2,15.9972317 2,14.754591 L2,5.25 C2,4.00735931 3.00735931,3 4.25,3 L19.7453641,3 Z M19.7453641,4.5 L4.25,4.5 C3.83578644,4.5 3.5,4.83578644 3.5,5.25 L3.5,14.754591 C3.5,15.1688046 3.83578644,15.504591 4.25,15.504591 L19.7453641,15.504591 C20.1595777,15.504591 20.4953641,15.1688046 20.4953641,14.754591 L20.4953641,5.25 C20.4953641,4.83578644 20.1595777,4.5 19.7453641,4.5 Z M17.25,12.5 C17.6642136,12.5 18,12.8357864 18,13.25 C18,13.6296958 17.7178461,13.943491 17.3517706,13.9931534 L17.25,14 L6.75,14 C6.33578644,14 6,13.6642136 6,13.25 C6,12.8703042 6.28215388,12.556509 6.64822944,12.5068466 L6.75,12.5 L17.25,12.5 Z M16.5,9 C17.0522847,9 17.5,9.44771525 17.5,10 C17.5,10.5522847 17.0522847,11 16.5,11 C15.9477153,11 15.5,10.5522847 15.5,10 C15.5,9.44771525 15.9477153,9 16.5,9 Z M10.5048752,9 C11.05716,9 11.5048752,9.44771525 11.5048752,10 C11.5048752,10.5522847 11.05716,11 10.5048752,11 C9.95259045,11 9.5048752,10.5522847 9.5048752,10 C9.5048752,9.44771525 9.95259045,9 10.5048752,9 Z M7.5048752,9 C8.05715995,9 8.5048752,9.44771525 8.5048752,10 C8.5048752,10.5522847 8.05715995,11 7.5048752,11 C6.95259045,11 6.5048752,10.5522847 6.5048752,10 C6.5048752,9.44771525 6.95259045,9 7.5048752,9 Z M13.5048752,9 C14.05716,9 14.5048752,9.44771525 14.5048752,10 C14.5048752,10.5522847 14.05716,11 13.5048752,11 C12.9525905,11 12.5048752,10.5522847 12.5048752,10 C12.5048752,9.44771525 12.9525905,9 13.5048752,9 Z M6,6 C6.55228475,6 7,6.44771525 7,7 C7,7.55228475 6.55228475,8 6,8 C5.44771525,8 5,7.55228475 5,7 C5,6.44771525 5.44771525,6 6,6 Z M8.9951248,6 C9.54740955,6 9.9951248,6.44771525 9.9951248,7 C9.9951248,7.55228475 9.54740955,8 8.9951248,8 C8.44284005,8 7.9951248,7.55228475 7.9951248,7 C7.9951248,6.44771525 8.44284005,6 8.9951248,6 Z M11.9951248,6 C12.5474095,6 12.9951248,6.44771525 12.9951248,7 C12.9951248,7.55228475 12.5474095,8 11.9951248,8 C11.44284,8 10.9951248,7.55228475 10.9951248,7 C10.9951248,6.44771525 11.44284,6 11.9951248,6 Z M14.9951248,6 C15.5474095,6 15.9951248,6.44771525 15.9951248,7 C15.9951248,7.55228475 15.5474095,8 14.9951248,8 C14.44284,8 13.9951248,7.55228475 13.9951248,7 C13.9951248,6.44771525 14.44284,6 14.9951248,6 Z M17.9951248,6 C18.5474095,6 18.9951248,6.44771525 18.9951248,7 C18.9951248,7.55228475 18.5474095,8 17.9951248,8 C17.44284,8 16.9951248,7.55228475 16.9951248,7 C16.9951248,6.44771525 17.44284,6 17.9951248,6 Z"; + + // Chats + public const string Chat = "M14.0038862,2.5 C20.3551608,2.5 25.5038862,7.64872538 25.5038862,14 C25.5038862,20.3512746 20.3551608,25.5 14.0038862,25.5 C12.0828262,25.5 10.2289934,25.0277557 8.57453454,24.1400553 L4.06949813,25.4927799 C3.40830889,25.6913248 2.71135661,25.3162775 2.51281166,24.6550883 C2.44236748,24.4204969 2.44239769,24.1703786 2.5128929,23.935823 L3.86597493,19.4333464 C2.97690068,17.777898 2.50388618,15.9226229 2.50388618,14 C2.50388618,7.64872538 7.65261155,2.5 14.0038862,2.5 Z M14.0038862,4 C8.48103868,4 4.00388618,8.4771525 4.00388618,14 C4.00388618,15.7703119 4.46384891,17.4718347 5.32571954,18.9725127 L5.48656853,19.2525809 L4.08316234,23.9225148 L8.75512584,22.5196672 L9.03501121,22.6802549 C10.5348218,23.5407899 12.2350195,24 14.0038862,24 C19.5267337,24 24.0038862,19.5228475 24.0038862,14 C24.0038862,8.4771525 19.5267337,4 14.0038862,4 Z M10.2538862,15.5 L14.7521489,15.5 C15.1663625,15.5 15.5021489,15.8357864 15.5021489,16.25 C15.5021489,16.6296958 15.219995,16.943491 14.8539195,16.9931534 L14.7521489,17 L10.2538862,17 C9.83967261,17 9.50388618,16.6642136 9.50388618,16.25 C9.50388618,15.8703042 9.78604006,15.556509 10.1521156,15.5068466 L10.2538862,15.5 L14.7521489,15.5 L10.2538862,15.5 Z M10.2538862,11 L17.7583662,11 C18.1725798,11 18.5083662,11.3357864 18.5083662,11.75 C18.5083662,12.1296958 18.2262123,12.443491 17.8601368,12.4931534 L17.7583662,12.5 L10.2538862,12.5 C9.83967261,12.5 9.50388618,12.1642136 9.50388618,11.75 C9.50388618,11.3703042 9.78604006,11.056509 10.1521156,11.0068466 L10.2538862,11 L17.7583662,11 L10.2538862,11 Z"; + + // Media + public const string Media = "M16.25 7.75a1.25 1.25 0 1 1-2.5 0 1.25 1.25 0 0 1 2.5 0Zm.667 9.242a1.78 1.78 0 0 1-.167.008h-1a.75.75 0 0 0 0 1.5h1c.966 0 1.75.784 1.75 1.75V21a.75.75 0 0 0 1.5 0v-.75a3.244 3.244 0 0 0-1.173-2.5A3.244 3.244 0 0 0 20 15.25v-9A3.25 3.25 0 0 0 16.75 3h-9.5A3.25 3.25 0 0 0 4 6.25v9c0 1.005.456 1.904 1.173 2.5A3.243 3.243 0 0 0 4 20.25V21a.75.75 0 0 0 1.5 0v-.75c0-.966.784-1.75 1.75-1.75h1a.75.75 0 0 0 0-1.5h-1c-.057 0-.113-.003-.168-.008l4.394-4.284a.75.75 0 0 1 1.047 0l4.394 4.284ZM7.25 4.5h9.5c.966 0 1.75.784 1.75 1.75v9c0 .342-.098.66-.267.93l-4.663-4.546a2.25 2.25 0 0 0-3.14 0l-4.663 4.545a1.742 1.742 0 0 1-.267-.929v-9c0-.966.784-1.75 1.75-1.75Zm4 12.5a.75.75 0 0 0 0 1.5h1.5a.75.75 0 0 0 0-1.5h-1.5Z"; + + // Layouts + public const string Layouts = "M2 5.75A2.75 2.75 0 0 1 4.75 3h14.5A2.75 2.75 0 0 1 22 5.75v12.5A2.75 2.75 0 0 1 19.25 21H4.75A2.75 2.75 0 0 1 2 18.25V5.75ZM4.75 4.5c-.69 0-1.25.56-1.25 1.25v12.5c0 .69.56 1.25 1.25 1.25h14.5c.69 0 1.25-.56 1.25-1.25V5.75c0-.69-.56-1.25-1.25-1.25H4.75Z"; + + // Three line Nav + public const string HamburgerUnread = "M19.25 8.5a2.75 2.75 0 1 0 0-5.5 2.75 2.75 0 0 0 0 5.5ZM15.576 6.503a3.768 3.768 0 0 1-.002-1.5H2.752l-.102.007a.75.75 0 0 0 .102 1.493h12.824ZM21.253 18h-18.5l-.102.007a.75.75 0 0 0 .102 1.493h18.5l.102-.007A.75.75 0 0 0 21.253 18ZM2.753 11.503h18.5a.75.75 0 0 1 .102 1.493l-.102.007h-18.5a.75.75 0 0 1-.102-1.493l.102-.007Z"; + + // Menus + public const string Menus = "M18.75,3 C19.940825,3 20.9156417,3.92516222 20.994809,5.09595127 L21,5.25 L21,18.75 C21,19.940825 20.074801,20.9156417 18.9040441,20.994809 L18.75,21 L5.25,21 C4.05913667,21 3.08435514,20.074801 3.00519082,18.9040441 L3,18.75 L3,5.25 C3,4.05913667 3.92516222,3.08435514 5.09595127,3.00519082 L5.25,3 L18.75,3 Z M18.75,4.5 L5.25,4.5 C4.8703075,4.5 4.55650958,4.78215688 4.50684668,5.14823019 L4.5,5.25 L4.5,18.75 C4.5,19.1296833 4.78215688,19.4434889 5.14823019,19.4931531 L5.25,19.5 L18.75,19.5 C19.1296833,19.5 19.4434889,19.2178347 19.4931531,18.8517677 L19.5,18.75 L19.5,5.25 C19.5,4.8703075 19.2178347,4.55650958 18.8517677,4.50684668 L18.75,4.5 Z M7.75,14.75 C8.30228,14.75 8.75,15.1977 8.75,15.75 C8.75,16.3023 8.30228,16.75 7.75,16.75 C7.19772,16.75 6.75,16.3023 6.75,15.75 C6.75,15.1977 7.19772,14.75 7.75,14.75 Z M16.7499,15 C17.1642,15 17.4999,15.3358 17.4999,15.75 C17.4999,16.1296833 17.2178188,16.4434889 16.8516887,16.4931531 L16.7499,16.5 L11.2501,16.5 C10.8358,16.5 10.5001,16.1642 10.5001,15.75 C10.5001,15.3703167 10.7821813,15.0565111 11.1483113,15.0068469 L11.2501,15 L16.7499,15 Z M7.75,11 C8.30228,11 8.75,11.4477 8.75,12 C8.75,12.5523 8.30228,13 7.75,13 C7.19772,13 6.75,12.5523 6.75,12 C6.75,11.4477 7.19772,11 7.75,11 Z M16.7499,11.25 C17.1642,11.25 17.4999,11.5858 17.4999,12 C17.4999,12.4142 17.1642,12.75 16.7499,12.75 L11.2501,12.75 C10.8358,12.75 10.5001,12.4142 10.5001,12 C10.5001,11.5858 10.8358,11.25 11.2501,11.25 L16.7499,11.25 Z M7.75,7.25 C8.30228,7.25 8.75,7.69772 8.75,8.25 C8.75,8.80228 8.30228,9.25 7.75,9.25 C7.19772,9.25 6.75,8.80228 6.75,8.25 C6.75,7.69772 7.19772,7.25 7.75,7.25 Z M16.75,7.5 C17.1642,7.5 17.5,7.83579 17.5,8.25 C17.5,8.66421 17.1642,9 16.75,9 L11.25,9 C10.8358,9 10.5,8.66421 10.5,8.25 C10.5,7.83579 10.8358,7.5 11.25,7.5 L16.75,7.5 Z"; + + // Date + public const string Date = "M21.75,3 C23.5449254,3 25,4.45507456 25,6.25 L25,21.75 C25,23.5449254 23.5449254,25 21.75,25 L6.25,25 C4.45507456,25 3,23.5449254 3,21.75 L3,6.25 C3,4.45507456 4.45507456,3 6.25,3 L21.75,3 Z M23.5,9.503 L4.5,9.503 L4.5,21.75 C4.5,22.7164983 5.28350169,23.5 6.25,23.5 L21.75,23.5 C22.7164983,23.5 23.5,22.7164983 23.5,21.75 L23.5,9.503 Z M16.9941406,12.234375 C17.7949259,12.234375 18.4296852,12.4472635 18.8984375,12.8730469 C19.3671898,13.2988303 19.6015625,13.8749964 19.6015625,14.6015625 C19.6015625,15.0195333 19.4941417,15.3915999 19.2792969,15.7177734 C19.0644521,16.0439469 18.7714862,16.3007803 18.4003906,16.4882813 C18.8457054,16.6953135 19.1884754,16.9785138 19.4287109,17.3378906 C19.6689465,17.6972674 19.7890625,18.1035134 19.7890625,18.5566406 C19.7890625,19.3066444 19.5351588,19.901365 19.0273437,20.3408203 C18.5195287,20.7802756 17.8437542,21 17,21 C16.1523395,21 15.4736354,20.7792991 14.9638672,20.3378906 C14.454099,19.8964822 14.1992187,19.3027381 14.1992187,18.5566406 C14.1992187,18.0996071 14.3203113,17.6894549 14.5625,17.3261719 C14.8046887,16.9628888 15.1445291,16.6835947 15.5820312,16.4882813 C15.2148419,16.3007803 14.9248058,16.0439469 14.7119141,15.7177734 C14.4990224,15.3915999 14.3925781,15.0195333 14.3925781,14.6015625 C14.3925781,13.8749964 14.6269508,13.2988303 15.0957031,12.8730469 C15.5644555,12.4472635 16.1972616,12.234375 16.9941406,12.234375 Z M11.9636719,12.3222656 L11.9636719,20.8828125 L10.5457031,20.8828125 L10.5457031,14.0332031 L8.45390625,14.7480469 L8.45390625,13.546875 L11.7820312,12.3222656 L11.9636719,12.3222656 Z M16.9882813,17.0742188 C16.5742167,17.0742188 16.2431653,17.2031237 15.9951172,17.4609375 C15.7470691,17.7187513 15.6230469,18.0605447 15.6230469,18.4863281 C15.6230469,18.904299 15.745116,19.23828 15.9892578,19.4882812 C16.2333997,19.7382825 16.5703104,19.8632812 17,19.8632812 C17.4296896,19.8632812 17.7646472,19.7421887 18.0048828,19.5 C18.2451184,19.2578113 18.3652344,18.919924 18.3652344,18.4863281 C18.3652344,18.064451 18.2392591,17.7236341 17.9873047,17.4638672 C17.7353503,17.2041003 17.4023458,17.0742188 16.9882813,17.0742188 Z M16.9941406,13.3769531 C16.6308576,13.3769531 16.3437511,13.4912098 16.1328125,13.7197266 C15.9218739,13.9482433 15.8164062,14.2597637 15.8164062,14.6542969 C15.8164062,15.0449238 15.9228505,15.3554676 16.1357422,15.5859375 C16.3486339,15.8164074 16.6367169,15.9316406 17,15.9316406 C17.3632831,15.9316406 17.6513661,15.8164074 17.8642578,15.5859375 C18.0771495,15.3554676 18.1835938,15.0449238 18.1835938,14.6542969 C18.1835938,14.2832013 18.0761729,13.9775403 17.8613281,13.7373047 C17.6464833,13.4970691 17.3574237,13.3769531 16.9941406,13.3769531 Z M21.75,4.5 L6.25,4.5 C5.28350169,4.5 4.5,5.28350169 4.5,6.25 L4.5,8.003 L23.5,8.003 L23.5,6.25 C23.5,5.28350169 22.7164983,4.5 21.75,4.5 Z"; + + // Lists + public const string Lists = "M7.24924 16C7.93921 16 8.49853 16.5593 8.49853 17.2493C8.49853 17.9393 7.93921 18.4986 7.24924 18.4986C6.55928 18.4986 5.99995 17.9393 5.99995 17.2493C5.99995 16.5593 6.55928 16 7.24924 16ZM10.75 16.5H21.25C21.6642 16.5 22 16.8358 22 17.25C22 17.6297 21.7178 17.9435 21.3517 17.9932L21.25 18H10.75C10.3357 18 9.99995 17.6642 9.99995 17.25C9.99995 16.8703 10.2821 16.5565 10.6482 16.5068L10.75 16.5ZM3.24904 11C3.93901 11 4.49833 11.5593 4.49833 12.2493C4.49833 12.9393 3.93901 13.4986 3.24904 13.4986C2.55908 13.4986 1.99976 12.9393 1.99976 12.2493C1.99976 11.5593 2.55908 11 3.24904 11ZM6.74976 11.5H21.25C21.6642 11.5 22 11.8358 22 12.25C22 12.6297 21.7178 12.9435 21.3517 12.9932L21.25 13H6.74976C6.33554 13 5.99976 12.6642 5.99976 12.25C5.99976 11.8703 6.28191 11.5565 6.64799 11.5068L6.74976 11.5ZM3.24924 6C3.93921 6 4.49853 6.55933 4.49853 7.24929C4.49853 7.93925 3.93921 8.49858 3.24924 8.49858C2.55928 8.49858 1.99995 7.93925 1.99995 7.24929C1.99995 6.55933 2.55928 6 3.24924 6ZM6.74995 6.5H21.25C21.6642 6.5 22 6.83579 22 7.25C22 7.6297 21.7178 7.94349 21.3517 7.99315L21.25 8H6.74995C6.33574 8 5.99995 7.66421 5.99995 7.25C5.99995 6.8703 6.28211 6.55651 6.64818 6.50685L6.74995 6.5Z"; + + // Textbox + public const string TextBox = "M18.25 3C19.7688 3 21 4.23122 21 5.75V18.25C21 19.7688 19.7688 21 18.25 21H5.75C4.23122 21 3 19.7688 3 18.25V5.75C3 4.23122 4.23122 3 5.75 3H18.25ZM18.25 4.5H5.75C5.05964 4.5 4.5 5.05964 4.5 5.75V18.25C4.5 18.9404 5.05964 19.5 5.75 19.5H18.25C18.9404 19.5 19.5 18.9404 19.5 18.25V5.75C19.5 5.05964 18.9404 4.5 18.25 4.5ZM14.25 11.5H6.75L6.64823 11.5068C6.28215 11.5565 6 11.8703 6 12.25C6 12.6642 6.33579 13 6.75 13H14.25L14.3518 12.9932C14.7178 12.9435 15 12.6297 15 12.25C15 11.8358 14.6642 11.5 14.25 11.5ZM6.75 15.5H17.25C17.6642 15.5 18 15.8358 18 16.25C18 16.6297 17.7178 16.9435 17.3518 16.9932L17.25 17H6.75C6.33579 17 6 16.6642 6 16.25C6 15.8703 6.28215 15.5565 6.64823 15.5068L6.75 15.5ZM17.25 7.5H6.75L6.64823 7.50685C6.28215 7.55651 6 7.8703 6 8.25C6 8.66421 6.33579 9 6.75 9H17.25L17.3518 8.99315C17.7178 8.94349 18 8.6297 18 8.25C18 7.83579 17.6642 7.5 17.25 7.5Z"; + + // Cursor 2 + public const string Cursor2 = "M5.5 3.48349C5.5 2.23523 6.93571 1.5331 7.92098 2.29951L21.4353 12.8119C22.5626 13.6887 21.9425 15.4958 20.5143 15.4958H13.6619C13.1574 15.4958 12.6806 15.7267 12.3676 16.1224L8.17661 21.4226C7.2945 22.5382 5.5 21.9145 5.5 20.4923L5.5 3.48349ZM20.5143 13.9958L7 3.48349L7 20.4923L11.191 15.192C11.7884 14.4365 12.6987 13.9958 13.6619 13.9958H20.5143Z"; + + // Settings + public const string Settings = "M14 9.50006C11.5147 9.50006 9.5 11.5148 9.5 14.0001C9.5 16.4853 11.5147 18.5001 14 18.5001C15.3488 18.5001 16.559 17.9066 17.3838 16.9666C18.0787 16.1746 18.5 15.1365 18.5 14.0001C18.5 13.5401 18.431 13.0963 18.3028 12.6784C17.7382 10.8381 16.0253 9.50006 14 9.50006ZM11 14.0001C11 12.3432 12.3431 11.0001 14 11.0001C15.6569 11.0001 17 12.3432 17 14.0001C17 15.6569 15.6569 17.0001 14 17.0001C12.3431 17.0001 11 15.6569 11 14.0001Z M21.7093 22.3948L19.9818 21.6364C19.4876 21.4197 18.9071 21.4515 18.44 21.7219C17.9729 21.9924 17.675 22.4693 17.6157 23.0066L17.408 24.8855C17.3651 25.273 17.084 25.5917 16.7055 25.682C14.9263 26.1061 13.0725 26.1061 11.2933 25.682C10.9148 25.5917 10.6336 25.273 10.5908 24.8855L10.3834 23.0093C10.3225 22.4731 10.0112 21.9976 9.54452 21.7281C9.07783 21.4586 8.51117 21.4269 8.01859 21.6424L6.29071 22.4009C5.93281 22.558 5.51493 22.4718 5.24806 22.1859C4.00474 20.8536 3.07924 19.2561 2.54122 17.5137C2.42533 17.1384 2.55922 16.7307 2.8749 16.4977L4.40219 15.3703C4.83721 15.0501 5.09414 14.5415 5.09414 14.0007C5.09414 13.4598 4.83721 12.9512 4.40162 12.6306L2.87529 11.5051C2.55914 11.272 2.42513 10.8638 2.54142 10.4882C3.08038 8.74734 4.00637 7.15163 5.24971 5.82114C5.51684 5.53528 5.93492 5.44941 6.29276 5.60691L8.01296 6.36404C8.50793 6.58168 9.07696 6.54881 9.54617 6.27415C10.0133 6.00264 10.3244 5.52527 10.3844 4.98794L10.5933 3.11017C10.637 2.71803 10.9245 2.39704 11.3089 2.31138C12.19 2.11504 13.0891 2.01071 14.0131 2.00006C14.9147 2.01047 15.8128 2.11485 16.6928 2.31149C17.077 2.39734 17.3643 2.71823 17.4079 3.11017L17.617 4.98937C17.7116 5.85221 18.4387 6.50572 19.3055 6.50663C19.5385 6.507 19.769 6.45838 19.9843 6.36294L21.7048 5.60568C22.0626 5.44818 22.4807 5.53405 22.7478 5.81991C23.9912 7.1504 24.9172 8.74611 25.4561 10.487C25.5723 10.8623 25.4386 11.2703 25.1228 11.5035L23.5978 12.6297C23.1628 12.95 22.9 13.4586 22.9 13.9994C22.9 14.5403 23.1628 15.0489 23.5988 15.3698L25.1251 16.4965C25.441 16.7296 25.5748 17.1376 25.4586 17.5131C24.9198 19.2536 23.9944 20.8492 22.7517 22.1799C22.4849 22.4657 22.0671 22.5518 21.7093 22.3948ZM16.263 22.1966C16.4982 21.4685 16.9889 20.8288 17.6884 20.4238C18.5702 19.9132 19.6536 19.8547 20.5841 20.2627L21.9281 20.8526C22.791 19.8538 23.4593 18.7013 23.8981 17.4552L22.7095 16.5778L22.7086 16.5771C21.898 15.98 21.4 15.0277 21.4 13.9994C21.4 12.9719 21.8974 12.0195 22.7073 11.4227L22.7085 11.4218L23.8957 10.545C23.4567 9.2988 22.7881 8.14636 21.9248 7.1477L20.5922 7.73425L20.5899 7.73527C20.1844 7.91463 19.7472 8.00722 19.3039 8.00663C17.6715 8.00453 16.3046 6.77431 16.1261 5.15465L16.1259 5.15291L15.9635 3.69304C15.3202 3.57328 14.6677 3.50872 14.013 3.50017C13.3389 3.50891 12.6821 3.57367 12.0377 3.69328L11.8751 5.15452C11.7625 6.16272 11.1793 7.05909 10.3019 7.56986C9.41937 8.0856 8.34453 8.14844 7.40869 7.73694L6.07273 7.14893C5.20949 8.14751 4.54092 9.29983 4.10196 10.5459L5.29181 11.4233C6.11115 12.0269 6.59414 12.9837 6.59414 14.0007C6.59414 15.0173 6.11142 15.9742 5.29237 16.5776L4.10161 17.4566C4.54002 18.7044 5.2085 19.8585 6.07205 20.8587L7.41742 20.2682C8.34745 19.8613 9.41573 19.9215 10.2947 20.4292C11.174 20.937 11.7593 21.832 11.8738 22.84L11.8744 22.8445L12.0362 24.3088C13.3326 24.5638 14.6662 24.5638 15.9626 24.3088L16.1247 22.8418C16.1491 22.6217 16.1955 22.4055 16.263 22.1966Z"; } } diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml index 08f47ca630..6a4ef8b8e2 100644 --- a/samples/ControlCatalog/MainView.xaml +++ b/samples/ControlCatalog/MainView.xaml @@ -1,13 +1,16 @@ + + + + #FF171717 + + + #FFF2F2F2 + + @@ -34,131 +46,204 @@ + - - - - - + + + + + + + + + + - + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IsVisible="{Binding IsDrawerOpened}" + VerticalContentAlignment="Center"> + Data="{StaticResource SearchIcon}" /> - - + Name="Icon" + Data="{StaticResource AppIcon}" /> - - - - - None - BorderOnly - Full - - - - - Default - Light - Dark - - - - - Fluent - Simple - - - - - None - Transparent - Blur - AcrylicBlur - Mica - - - - - LeftToRight - RightToLeft - - - - - + + + + + + + + + + + + - + + + Transparent + + diff --git a/samples/ControlCatalog/MainView.xaml.cs b/samples/ControlCatalog/MainView.xaml.cs index 8d4da7fec2..20f1ab586b 100644 --- a/samples/ControlCatalog/MainView.xaml.cs +++ b/samples/ControlCatalog/MainView.xaml.cs @@ -3,18 +3,13 @@ using System.Threading.Tasks; using Avalonia; using Avalonia.Controls; using Avalonia.Input; -using Avalonia.Media; -using Avalonia.Media.Immutable; using Avalonia.Styling; -using ControlCatalog.Models; using ControlCatalog.ViewModels; namespace ControlCatalog { public partial class MainView : DrawerPage { - private readonly TransparentStyles _transparentStyles = new(); - public MainView() { InitializeComponent(); @@ -35,6 +30,11 @@ namespace ControlCatalog SizeChanged += OnDrawerSizeChanged; UpdateAdaptiveLayout(); + + if (Application.Current is { } app) + { + app.RequestedThemeVariant = ThemeVariant.Default; + } } private void MainView_Unloaded(object? sender, Avalonia.Interactivity.RoutedEventArgs e) @@ -89,59 +89,6 @@ namespace ControlCatalog } } - private void Themes_SelectionChanged(object? sender, SelectionChangedEventArgs e) - { - if (e.AddedItems.Count > 0 && e.AddedItems[0] is CatalogTheme theme) - { - App.SetCatalogThemes(theme); - } - } - - private void ThemeVariants_SelectionChanged(object? sender, SelectionChangedEventArgs e) - { - if (Application.Current is { } app && e.AddedItems.Count > 0 && e.AddedItems[0] is ThemeVariant themeVariant) - { - app.RequestedThemeVariant = themeVariant; - } - } - - private void FlowDirection_SelectionChanged(object? sender, SelectionChangedEventArgs e) - { - if (TopLevel.GetTopLevel(this) is { } topLevel && e.AddedItems.Count > 0 && e.AddedItems[0] is FlowDirection flowDirection) - { - topLevel.FlowDirection = flowDirection; - } - } - - private void Decorations_SelectionChanged(object? sender, SelectionChangedEventArgs e) - { - if (TopLevel.GetTopLevel(this) is Window window && e.AddedItems.Count > 0 && e.AddedItems[0] is WindowDecorations systemDecorations) - { - window.WindowDecorations = systemDecorations; - } - } - - private void TransparencyLevels_SelectionChanged(object? sender, SelectionChangedEventArgs e) - { - if (TopLevel.GetTopLevel(this) is { } topLevel && e.AddedItems.Count > 0 && e.AddedItems[0] is WindowTransparencyLevel transparencyLevel) - { - topLevel.TransparencyLevelHint = [transparencyLevel]; - - if (topLevel.ActualTransparencyLevel != WindowTransparencyLevel.None && - transparencyLevel != WindowTransparencyLevel.None) - { - topLevel.Background = new ImmutableSolidColorBrush(Colors.Gray, 0.2); - if (!topLevel.Styles.Contains(_transparentStyles)) - topLevel.Styles.Add(_transparentStyles); - } - else - { - topLevel.Background = null; - topLevel.Styles.Remove(_transparentStyles); - } - } - } - protected override void OnDataContextChanged(EventArgs e) { base.OnDataContextChanged(e); @@ -149,6 +96,8 @@ namespace ControlCatalog if (ViewModel != null) { ViewModel.Navigator = NavPage; + + ViewModel.NavigateToItem(ViewModel.HomeItem); } } @@ -164,8 +113,6 @@ namespace ControlCatalog UpdateAdaptiveLayout(); var topLevel = TopLevel.GetTopLevel(this)!; - if (topLevel is Window window) - ViewModel.SelectedDecorationIndex = (int)window.WindowDecorations; var insets = topLevel.InsetsManager; if (insets != null) @@ -197,8 +144,6 @@ namespace ControlCatalog ViewModel.IsSystemBarVisible = insets.IsSystemBarVisible ?? true; }; } - - ViewModel.SelectedPageIndex = 0; } private async void AvaloniaIcon_OnTapped(object? sender, TappedEventArgs e) diff --git a/samples/ControlCatalog/MainWindow.xaml b/samples/ControlCatalog/MainWindow.xaml index 82478ebdd0..8929958878 100644 --- a/samples/ControlCatalog/MainWindow.xaml +++ b/samples/ControlCatalog/MainWindow.xaml @@ -12,7 +12,8 @@ CanMaximize="{Binding CanMaximize}" WindowDrawnDecorations.TitleBarDecorations="{Binding TitleBarDecorations}" Win32Properties.WindowCornerPreference="{Binding Win32WindowCornerPreference}" - x:Class="ControlCatalog.MainWindow" WindowState="{Binding WindowState, Mode=TwoWay}" + x:Class="ControlCatalog.MainWindow" + WindowState="{Binding SettingsViewModel.WindowState, Mode=TwoWay}" x:DataType="vm:MainWindowViewModel"> @@ -59,20 +60,5 @@ - - - - - - diff --git a/samples/ControlCatalog/Models/HomeSection.cs b/samples/ControlCatalog/Models/HomeSection.cs index a7c3bdeee3..03a55010d1 100644 --- a/samples/ControlCatalog/Models/HomeSection.cs +++ b/samples/ControlCatalog/Models/HomeSection.cs @@ -1,10 +1,30 @@ using System.Collections.Generic; -using ControlCatalog.ViewModels; +using System.Linq; +using Avalonia.Media; +using ControlCatalog.Pages; +using MiniMvvm; namespace ControlCatalog.Models; -public class HomeSection(string title, IReadOnlyList items) +public class HomeSection : ViewModelBase { - public string Title { get; } = title; - public IReadOnlyList Items { get; } = items; + public string Title { get; } + public StreamGeometry IconData { get; } + public IReadOnlyList? Items { get; set; } + + public bool IsSectionVisible => Items?.Any(x => x.IsVisible) == true; + + public PageItem PageItem { get; } + + public HomeSection(string title, StreamGeometry iconData) + { + Title = title; + IconData = iconData; + PageItem = new PageItem(title, () => new SectionPage(this), iconData, "", null); + } + + public void RaiseSectionVisibilityChanged() + { + RaisePropertyChanged(nameof(IsSectionVisible)); + } } diff --git a/samples/ControlCatalog/Models/PageItem.cs b/samples/ControlCatalog/Models/PageItem.cs index af8a361101..f4521cfe1d 100644 --- a/samples/ControlCatalog/Models/PageItem.cs +++ b/samples/ControlCatalog/Models/PageItem.cs @@ -3,17 +3,27 @@ using System.Globalization; using System.Text; using Avalonia.Controls; using Avalonia.Media; +using MiniMvvm; namespace ControlCatalog.Models; -public class PageItem(string header, Func factory, StreamGeometry iconData, string description, string section) +public class PageItem(string header, Func factory, StreamGeometry iconData, string description, HomeSection? section) : ViewModelBase { public string Header { get; } = header; public StreamGeometry? IconData { get; } = iconData; public string? Description { get; } = description; - private string SearchKey { get; } = CreateSearchKey(header, section); + public string Section { get; } = section?.Title ?? ""; + private string SearchKey { get; } = CreateSearchKey(header, section?.Title ?? ""); - public bool IsVisible { get; set; } = true; + public bool IsVisible + { + get; + set + { + RaiseAndSetIfChanged(ref field, value); + section?.RaiseSectionVisibilityChanged(); + } + } = true; public Page CreatePage() => factory(); diff --git a/samples/ControlCatalog/NavHeaderItem.xaml b/samples/ControlCatalog/NavHeaderItem.xaml deleted file mode 100644 index 6867661ebb..0000000000 --- a/samples/ControlCatalog/NavHeaderItem.xaml +++ /dev/null @@ -1,101 +0,0 @@ - - - - - - #99FFFFFF - #FF1F1F1F - #FF000000 - #FF171717 - - - #99000000 - #FFE6E6E6 - #FFFFFFFF - #FFF2F2F2 - - - 36 - 1 1 1 1 #2000, 0 0 1 1 #2fff - - - - Disabled - - Test - - Test - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/samples/ControlCatalog/Pages/HomePage.xaml b/samples/ControlCatalog/Pages/HomePage.xaml index 03c825c2f6..9d9596dc0f 100644 --- a/samples/ControlCatalog/Pages/HomePage.xaml +++ b/samples/ControlCatalog/Pages/HomePage.xaml @@ -4,58 +4,10 @@ xmlns:viewModels="using:ControlCatalog.ViewModels" xmlns:controlCatalog="using:ControlCatalog" xmlns:models="clr-namespace:ControlCatalog.Models" + xmlns:controls="using:ControlCatalog.Controls" x:Class="ControlCatalog.Pages.HomePage" Header="Home"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -101,48 +53,10 @@ - + - - - - - - - - - - - - + diff --git a/samples/ControlCatalog/Pages/SectionPage.axaml b/samples/ControlCatalog/Pages/SectionPage.axaml new file mode 100644 index 0000000000..4875d87726 --- /dev/null +++ b/samples/ControlCatalog/Pages/SectionPage.axaml @@ -0,0 +1,15 @@ + + + diff --git a/samples/ControlCatalog/Pages/SectionPage.axaml.cs b/samples/ControlCatalog/Pages/SectionPage.axaml.cs new file mode 100644 index 0000000000..dc58c1fbec --- /dev/null +++ b/samples/ControlCatalog/Pages/SectionPage.axaml.cs @@ -0,0 +1,23 @@ +using System; +using Avalonia.Controls; +using Avalonia.Controls.Primitives; +using ControlCatalog.Models; +using ControlCatalog.ViewModels; + +namespace ControlCatalog.Pages +{ + public partial class SectionPage : ContentPage + { + public SectionPage(HomeSection homeSection) + { + InitializeComponent(); + + DataContext = new SectionViewModel(homeSection); + } + + public SectionPage() + { + InitializeComponent(); + } + } +} diff --git a/samples/ControlCatalog/Pages/SettingsPage.axaml b/samples/ControlCatalog/Pages/SettingsPage.axaml new file mode 100644 index 0000000000..d935f96500 --- /dev/null +++ b/samples/ControlCatalog/Pages/SettingsPage.axaml @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + None + BorderOnly + Full + + + + + + + + + + + Fluent + Simple + + + + + + + + + + + Default + Light + Dark + + + + + + + + + + + None + Transparent + Blur + AcrylicBlur + Mica + + + + + + + + + + + LeftToRight + RightToLeft + + + + + + + + + + + + + diff --git a/samples/ControlCatalog/Pages/SettingsPage.axaml.cs b/samples/ControlCatalog/Pages/SettingsPage.axaml.cs new file mode 100644 index 0000000000..db4213a3f9 --- /dev/null +++ b/samples/ControlCatalog/Pages/SettingsPage.axaml.cs @@ -0,0 +1,93 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Media; +using Avalonia.Media.Immutable; +using Avalonia.Styling; +using ControlCatalog.Models; +using ControlCatalog.ViewModels; + +namespace ControlCatalog.Pages +{ + public partial class SettingsPage : ContentPage + { + private readonly TransparentStyles _transparentStyles = new(); + + public SettingsPage(SettingsViewModel settingsViewModel) + { + InitializeComponent(); + + DataContext = settingsViewModel; + } + + public SettingsPage() + { + InitializeComponent(); + DataContext = new SettingsViewModel(); + } + + protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) + { + base.OnAttachedToVisualTree(e); + + if (DataContext is SettingsViewModel viewModel) + { + var topLevel = TopLevel.GetTopLevel(this)!; + if (topLevel is Window window) + viewModel.SelectedDecorationIndex = (int)window.WindowDecorations; + } + } + + private void Decorations_SelectionChanged(object? sender, SelectionChangedEventArgs e) + { + if (TopLevel.GetTopLevel(this) is Window window && e.AddedItems.Count > 0 && e.AddedItems[0] is WindowDecorations systemDecorations) + { + window.WindowDecorations = systemDecorations; + } + } + + private void Themes_SelectionChanged(object? sender, SelectionChangedEventArgs e) + { + if (e.AddedItems.Count > 0 && e.AddedItems[0] is CatalogTheme theme) + { + App.SetCatalogThemes(theme); + } + } + + private void ThemeVariants_SelectionChanged(object? sender, SelectionChangedEventArgs e) + { + if (Application.Current is { } app && e.AddedItems.Count > 0 && e.AddedItems[0] is ThemeVariant themeVariant) + { + app.RequestedThemeVariant = themeVariant; + } + } + + private void FlowDirection_SelectionChanged(object? sender, SelectionChangedEventArgs e) + { + if (TopLevel.GetTopLevel(this) is { } topLevel && e.AddedItems.Count > 0 && e.AddedItems[0] is FlowDirection flowDirection) + { + topLevel.FlowDirection = flowDirection; + } + } + + private void TransparencyLevels_SelectionChanged(object? sender, SelectionChangedEventArgs e) + { + if (TopLevel.GetTopLevel(this) is { } topLevel && e.AddedItems.Count > 0 && e.AddedItems[0] is WindowTransparencyLevel transparencyLevel) + { + topLevel.TransparencyLevelHint = [transparencyLevel]; + + if (topLevel.ActualTransparencyLevel != WindowTransparencyLevel.None && + transparencyLevel != WindowTransparencyLevel.None) + { + topLevel.Background = new ImmutableSolidColorBrush(Colors.Gray, 0.2); + if (!topLevel.Styles.Contains(_transparentStyles)) + topLevel.Styles.Add(_transparentStyles); + } + else + { + topLevel.Background = null; + topLevel.Styles.Remove(_transparentStyles); + } + } + } + } +} diff --git a/samples/ControlCatalog/ScrollPage.xaml b/samples/ControlCatalog/ScrollPage.xaml deleted file mode 100644 index 8c6157018f..0000000000 --- a/samples/ControlCatalog/ScrollPage.xaml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs b/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs index 0c4edb29a5..a98901d286 100644 --- a/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs +++ b/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs @@ -1,25 +1,27 @@ -using Avalonia.Controls; -using Avalonia.Controls.ApplicationLifetimes; -using Avalonia.Controls.Chrome; -using Avalonia.Dialogs; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Runtime.CompilerServices; using Avalonia; -using Avalonia.Collections; +using Avalonia.Controls; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Controls.Chrome; +using Avalonia.Dialogs; +using Avalonia.Media; +using Avalonia.Styling; using ControlCatalog.Models; +using ControlCatalog.Pages; using MiniMvvm; namespace ControlCatalog.ViewModels { partial class MainWindowViewModel : ViewModelBase { - private readonly AvaloniaList _filteredPages = []; + public SettingsViewModel SettingsViewModel { get; } = new SettingsViewModel(); - private bool _ignoreListChange; - private PageItem? _currentItem; + public PageItem HomeItem { get; } = new PageItem("Home", () => new HomePage(), StreamGeometry.Parse(Icons.Home), "Overview of everything in the catalog", null); + public PageItem SettingsItem { get; } public MainWindowViewModel() { @@ -36,17 +38,29 @@ namespace ControlCatalog.ViewModels { (App.Current?.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.Shutdown(); }); - NavigateToPageCommand = MiniCommand.Create(NavigateToPage); + SettingsItem = new PageItem("Settings", () => new SettingsPage(SettingsViewModel), StreamGeometry.Parse(Icons.Settings), "Overview of everything in the catalog", null); + NavigateToPageCommand = MiniCommand.Create(NavigateToItem); + SettingsCommand = MiniCommand.Create(async () => + { + if (CurrentPageItem == SettingsItem) + return; - WindowState = WindowState.Normal; + if (Navigator is { } navigator) + { + NavigateToItem(SettingsItem); + } + }); - WindowStates = new WindowState[] + HomeCommand = MiniCommand.Create(async () => { - WindowState.Minimized, - WindowState.Normal, - WindowState.Maximized, - WindowState.FullScreen, - }; + if (CurrentPageItem == HomeItem) + return; + + if (Navigator is { } navigator) + { + NavigateToItem(HomeItem); + } + }); TitleBarHeight = -1; CanResize = true; @@ -60,8 +74,6 @@ namespace ControlCatalog.ViewModels // Home page doesn't have a section title and should be excluded from this list field ??= _pageSections.Where(s => !string.IsNullOrEmpty(s.Title)).ToArray(); - public IReadOnlyList Pages => _filteredPages; - public INavigation? Navigator { get; internal set; } public bool ExtendClientAreaEnabled @@ -76,55 +88,55 @@ namespace ControlCatalog.ViewModels set => RaiseAndSetIfChanged(ref field, value); } - public WindowState WindowState + public bool IsSystemBarVisible { get; set => RaiseAndSetIfChanged(ref field, value); } - public WindowState[] WindowStates + public bool DisplayEdgeToEdge { get; set => RaiseAndSetIfChanged(ref field, value); } - public bool IsSystemBarVisible + public Thickness SafeAreaPadding { get; set => RaiseAndSetIfChanged(ref field, value); } - public bool DisplayEdgeToEdge + public bool CanResize { get; set => RaiseAndSetIfChanged(ref field, value); } - public Thickness SafeAreaPadding + public bool CanMinimize { get; set => RaiseAndSetIfChanged(ref field, value); } - public bool CanResize + public bool CanMaximize { get; set => RaiseAndSetIfChanged(ref field, value); } - public bool CanMinimize + public bool ExpandAllSections { get; set => RaiseAndSetIfChanged(ref field, value); } - public bool CanMaximize + public string? OpenedSection { get; set => RaiseAndSetIfChanged(ref field, value); } - public int SelectedDecorationIndex + public ControlTheme? DecorationsTheme { get; set => RaiseAndSetIfChanged(ref field, value); @@ -166,21 +178,10 @@ namespace ControlCatalog.ViewModels set => SetTitleBarDecoration(TitleBarDecorations.CloseButton, value); } - public int SelectedPageIndex + public PageItem? CurrentPageItem { get; - set - { - RaiseAndSetIfChanged(ref field, value); - - if (!_ignoreListChange) - { - NavigateTo(field); - - if (DisplayMode == SplitViewDisplayMode.CompactOverlay || DisplayMode == SplitViewDisplayMode.Overlay) - IsDrawerOpened = false; - } - } + set => RaiseAndSetIfChanged(ref field, value); } public bool IsDrawerOpened @@ -226,6 +227,10 @@ namespace ControlCatalog.ViewModels public MiniCommand NavigateToPageCommand { get; } + public MiniCommand SettingsCommand { get; } + + public MiniCommand HomeCommand { get; } + /// /// A required DateTime which should demonstrate validation for the DateTimePicker /// @@ -245,80 +250,60 @@ namespace ControlCatalog.ViewModels set => RaiseAndSetIfChanged(ref field, value); } - public void NavigateToPage(PageItem item) + public void NavigateToItem(PageItem item) { // Clear any active search so the target is present in the filtered list. if (!string.IsNullOrEmpty(Query)) Query = ""; - var index = _filteredPages.IndexOf(item); - if (index >= 0) - SelectedPageIndex = index; + NavigateTo(item); } public void Filter(string? query = "") { - try - { - _ignoreListChange = true; - _filteredPages.Clear(); + ExpandAllSections = false; - // Left panel items are sorted alphabetically - var allPages = _pageSections - .SelectMany(cat => cat.Items) - .OrderBy(p => p.Header == "Home" ? 0 : 1) - .ThenBy(p => p.Header); + // Left panel items are sorted alphabetically + var allPages = _pageSections + .SelectMany(cat => cat.Items?.ToArray() ?? Array.Empty()) + .OrderBy(p => p.Header); - if (string.IsNullOrWhiteSpace(query)) - { - _filteredPages.AddRange(allPages); - } - else - { - var querySearchKey = PageItem.CreateSearchKey(query); + var querySearchKey = query != null ? PageItem.CreateSearchKey(query) : ""; + var isDefaultVisible = string.IsNullOrWhiteSpace(query) || string.IsNullOrWhiteSpace(querySearchKey); - if (querySearchKey.Length == 0) - { - _filteredPages.AddRange(allPages); - } - else - { - foreach (var item in allPages) - { - if (item.MatchesSearch(querySearchKey)) - { - _filteredPages.Add(item); - } - } - } - } + foreach (var page in allPages) + { + page.IsVisible = isDefaultVisible; } - finally + + if (!string.IsNullOrWhiteSpace(querySearchKey)) { - _ignoreListChange = false; - if (_currentItem != null) + ExpandAllSections = true; + foreach (var item in allPages) { - var newIndex = _filteredPages.IndexOf(_currentItem); - if (newIndex != -1) + if (item.MatchesSearch(querySearchKey)) { - SelectedPageIndex = newIndex; + item.IsVisible = true; } } } } - private async void NavigateTo(int pageIndex) + private async void NavigateTo(PageItem? item) { - if (pageIndex < 0 || pageIndex >= Pages.Count || Navigator is null) + if (item is null || Navigator is null) return; - var item = Pages[pageIndex]; var page = item.CreatePage(); - if (page.GetType() != Navigator.NavigationStack.LastOrDefault()?.GetType()) + if (item != CurrentPageItem) { - _currentItem = item; + CurrentPageItem = item; + OpenedSection = item.Section; await Navigator.ReplaceAsync(page); + + if (DisplayMode == SplitViewDisplayMode.CompactOverlay || DisplayMode == SplitViewDisplayMode.Overlay) + IsDrawerOpened = false; } } } diff --git a/samples/ControlCatalog/ViewModels/MainWindowViewModel_PageList.cs b/samples/ControlCatalog/ViewModels/MainWindowViewModel_PageList.cs index 3a87b098e2..0ace72b999 100644 --- a/samples/ControlCatalog/ViewModels/MainWindowViewModel_PageList.cs +++ b/samples/ControlCatalog/ViewModels/MainWindowViewModel_PageList.cs @@ -1,10 +1,10 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; using Avalonia.Controls; -using ControlCatalog.Pages; using Avalonia.Media; using ControlCatalog.Models; -using System.Threading.Tasks; +using ControlCatalog.Pages; namespace ControlCatalog.ViewModels; @@ -12,11 +12,7 @@ partial class MainWindowViewModel { private readonly HomeSection[] _pageSections = [ - Section("", s => - { - s.Add("Home", Icons.Home, "Overview of everything in the catalog"); - }), - Section("Basic Input", s => + Section("Basic Input", Icons.Cursor2, s => { s.Add("Buttons", Icons.CursorClick, "Button, RepeatButton, ToggleButton and friends"); s.Add("ButtonSpinner", Icons.Spinner, "Content with increment and decrement buttons"); @@ -28,14 +24,14 @@ partial class MainWindowViewModel s.Add("Slider", Icons.Tune, "Select a value from a continuous range"); s.Add("ToggleSwitch", Icons.Toggle, "An on/off switch with a sliding knob"); }), - Section("Text", s => + Section("Text", Icons.TextBox, s => { s.Add("AutoCompleteBox", Icons.TextInput, "Text input with completion suggestions"); s.Add("Label", Icons.Tag, "Captions with access keys for other controls"); s.Add("TextBox", Icons.TextInput, "Single- and multi-line text editing"); s.Add("TextBlock", Icons.TextInput, "Styled read-only text display"); }), - Section("Collections & Data", s => + Section("Collections & Data", Icons.Lists, s => { s.Add("Carousel", Icons.Slides, "Cycle through a collection of items"); s.Add("ListBox", Icons.List, "A selectable, virtualized list of items"); @@ -44,13 +40,13 @@ partial class MainWindowViewModel s.Add("TableView", Icons.Grid, "Tabular data with resizable, sortable columns"); s.Add("TreeView", Icons.Tree, "Hierarchical data with expandable nodes"); }), - Section("Date & Time", s => + Section("Date & Time", Icons.Date, s => { s.Add("Calendar", Icons.Calendar, "A month calendar for selecting dates"); s.Add("CalendarDatePicker", Icons.Calendar, "A date picker with a drop-down calendar"); s.Add("Date/Time Picker", Icons.Clock, "Spinner-style date and time pickers"); }), - Section("Menus & Flyouts", s => + Section("Menus & Flyouts", Icons.Menus, s => { s.Add("CommandBar", Icons.Terminal, "A toolbar of commands with an overflow menu"); s.Add("ContextFlyout", Icons.Menu, "Attach flyouts shown on right-click"); @@ -58,7 +54,7 @@ partial class MainWindowViewModel s.Add("Flyouts", Icons.Flyout, "Lightweight popups anchored to controls"); s.Add("Menu", Icons.Menu, "Menu bars with nested menu items"); }), - Section("Navigation & Pages", s => + Section("Navigation & Pages", Icons.HamburgerUnread, s => { s.Add("CarouselPage", Icons.Slides, "Swipeable page-based navigation"); s.Add("ContentPage", Icons.Document, "A page that hosts a single content view"); @@ -69,7 +65,7 @@ partial class MainWindowViewModel s.Add("TabControl", Icons.Tab, "Switch between tabbed content views"); s.Add("TabStrip", Icons.Tab, "A standalone strip of selectable tabs"); }), - Section("Layout", s => + Section("Layout", Icons.Layouts, s => { s.Add("Border", Icons.Border, "Decorate elements with borders and corner radii"); s.Add("Canvas", Icons.Canvas, "Position children at explicit coordinates"); @@ -83,7 +79,7 @@ partial class MainWindowViewModel s.Add("Viewbox", Icons.Viewbox, "Scale content to fit available space"); s.Add("WrapPanel", Icons.Layout, "Wrap children onto multiple lines"); }), - Section("Media & Graphics", s => + Section("Media & Graphics", Icons.Media, s => { s.Add("Acrylic", Icons.Blur, "Translucent acrylic window materials"); s.Add("BitmapCache", Icons.Lightning, "Cache visuals as bitmaps for performance"); @@ -94,7 +90,7 @@ partial class MainWindowViewModel s.Add("OpenGL Lease", Icons.Cube3D, "Low-level access to the OpenGL context"); s.Add("TransitioningContentControl", Icons.Transition, "Animate between content changes"); }), - Section("Status & Feedback", s => + Section("Status & Feedback", Icons.Chat, s => { s.Add("AdornerLayer", Icons.Sparkle, "Overlay visuals on top of other controls"); s.Add("Data Validation", Icons.Shield, "Display validation errors from bindings"); @@ -103,7 +99,7 @@ partial class MainWindowViewModel s.Add("ProgressBar", Icons.Progress, "Determinate and indeterminate progress"); s.Add("ToolTip", Icons.Tooltip, "Hover hints for any control"); }), - Section("Interaction", s => + Section("Interaction", Icons.KeyboardFloat, s => { s.Add("Accelerator", Icons.Keyboard, "Keyboard shortcuts that invoke commands"); s.Add("Clipboard", Icons.Clipboard, "Read from and write to the system clipboard"); @@ -113,7 +109,7 @@ partial class MainWindowViewModel s.Add("Gestures", Icons.Gesture, "Tap, scroll and pinch gesture recognition"); s.Add("Pointers", Icons.Cursor, "Raw pointer input and capture"); }), - Section("Window & Platform", s => + Section("Window & Platform", Icons.DesktopMobile, s => { s.Add("Native Embed", Icons.Puzzle, "Host native platform controls"); s.Add("Platform Information", Icons.Info, "Runtime platform and capability info"); @@ -124,19 +120,22 @@ partial class MainWindowViewModel }) ]; - private static HomeSection Section(string title, Action builderCallback) + private static HomeSection Section(string title, string iconPath, Action builderCallback) { - var builder = new HomeSectionBuilder(title); + var iconGeometry = StreamGeometry.Parse(iconPath); + var section = new HomeSection(title, iconGeometry); + var builder = new HomeSectionBuilder(section); builderCallback(builder); - return new HomeSection(title, builder.ToArray()); + section.Items = builder.ToArray(); + return section; } - private class HomeSectionBuilder(string title) : List + private class HomeSectionBuilder(HomeSection section) : List { public void Add(string header, string iconPath, string description) where TPageType : Page, new() { var iconGeometry = StreamGeometry.Parse(iconPath); - Add(new PageItem(header, () => new TPageType(), iconGeometry, description, title)); + Add(new PageItem(header, () => new TPageType(), iconGeometry, description, section)); } public async virtual Task Navigate(INavigation navigation) { } diff --git a/samples/ControlCatalog/ViewModels/SectionViewModel.cs b/samples/ControlCatalog/ViewModels/SectionViewModel.cs new file mode 100644 index 0000000000..992a4bc334 --- /dev/null +++ b/samples/ControlCatalog/ViewModels/SectionViewModel.cs @@ -0,0 +1,10 @@ +using ControlCatalog.Models; +using MiniMvvm; + +namespace ControlCatalog.ViewModels +{ + internal class SectionViewModel(HomeSection homeSection) : ViewModelBase + { + public HomeSection HomeSection { get; } = homeSection; + } +} diff --git a/samples/ControlCatalog/ViewModels/SettingsViewModel.cs b/samples/ControlCatalog/ViewModels/SettingsViewModel.cs new file mode 100644 index 0000000000..5fefc6cf93 --- /dev/null +++ b/samples/ControlCatalog/ViewModels/SettingsViewModel.cs @@ -0,0 +1,57 @@ +using Avalonia.Controls; +using MiniMvvm; + +namespace ControlCatalog.ViewModels +{ + public class SettingsViewModel : ViewModelBase + { + public SettingsViewModel() + { + WindowStates = new WindowState[] + { + WindowState.Minimized, + WindowState.Normal, + WindowState.Maximized, + WindowState.FullScreen, + }; + + WindowState = WindowState.Normal; + } + + public WindowState WindowState + { + get; + set => RaiseAndSetIfChanged(ref field, value); + } + + public int SelectedDecorationIndex + { + get; + set => RaiseAndSetIfChanged(ref field, value); + } + + public int SelectedThemeVariantIndex + { + get; + set => RaiseAndSetIfChanged(ref field, value); + } + + public int SelectedTransparencyLevelIndex + { + get; + set => RaiseAndSetIfChanged(ref field, value); + } + + public int SelectedFlowDirectionIndex + { + get; + set => RaiseAndSetIfChanged(ref field, value); + } + + public WindowState[] WindowStates + { + get; + set => RaiseAndSetIfChanged(ref field, value); + } + } +}