diff --git a/Perspex.Controls/IMenu.cs b/Perspex.Controls/IMenu.cs new file mode 100644 index 0000000000..5943007856 --- /dev/null +++ b/Perspex.Controls/IMenu.cs @@ -0,0 +1,13 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2015 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Controls +{ + internal interface IMenu + { + void ChildPointerEnter(MenuItem item); + } +} diff --git a/Perspex.Controls/Menu.cs b/Perspex.Controls/Menu.cs index 266cbb5b1b..79773ea7fd 100644 --- a/Perspex.Controls/Menu.cs +++ b/Perspex.Controls/Menu.cs @@ -4,11 +4,12 @@ // // ----------------------------------------------------------------------- -using Perspex.Controls.Generators; - namespace Perspex.Controls { - public class Menu : ItemsControl + using System.Linq; + using Perspex.LogicalTree; + + public class Menu : ItemsControl, IMenu { private static readonly ItemsPanelTemplate DefaultPanel = new ItemsPanelTemplate(() => new StackPanel { Orientation = Orientation.Horizontal }); @@ -17,5 +18,18 @@ namespace Perspex.Controls { ItemsPanelProperty.OverrideDefaultValue(typeof(Menu), DefaultPanel); } + + void IMenu.ChildPointerEnter(MenuItem item) + { + var children = this.GetLogicalChildren().Cast(); + + if (children.Any(x => x.IsSubMenuOpen)) + { + foreach (MenuItem i in this.GetLogicalChildren()) + { + i.IsSubMenuOpen = i == item; + } + } + } } } diff --git a/Perspex.Controls/MenuItem.cs b/Perspex.Controls/MenuItem.cs index 919511e2df..3fabb086b0 100644 --- a/Perspex.Controls/MenuItem.cs +++ b/Perspex.Controls/MenuItem.cs @@ -8,15 +8,35 @@ namespace Perspex.Controls { using Perspex.Controls.Primitives; using Perspex.Input; + using Perspex.LogicalTree; + using System.Windows.Input; public class MenuItem : HeaderedItemsControl { + public static readonly PerspexProperty CommandProperty = + Button.CommandProperty.AddOwner(); + + public static readonly PerspexProperty CommandParameterProperty = + Button.CommandParameterProperty.AddOwner(); + public static readonly PerspexProperty IconProperty = PerspexProperty.Register("Icon"); public static readonly PerspexProperty IsSubMenuOpenProperty = PerspexProperty.Register("IsSubMenuOpen"); + public ICommand Command + { + get { return this.GetValue(CommandProperty); } + set { this.SetValue(CommandProperty, value); } + } + + public object CommandParameter + { + get { return this.GetValue(CommandParameterProperty); } + set { this.SetValue(CommandParameterProperty, value); } + } + public object Icon { get { return this.GetValue(IconProperty); } @@ -29,10 +49,20 @@ namespace Perspex.Controls set { this.SetValue(IsSubMenuOpenProperty, value); } } + protected override void OnPointerEnter(PointerEventArgs e) + { + base.OnPointerEnter(e); + this.GetLogicalParent()?.ChildPointerEnter(this); + } + protected override void OnPointerPressed(PointerPressEventArgs e) { base.OnPointerPressed(e); - this.IsSubMenuOpen = !this.IsSubMenuOpen; + + if (!this.Classes.Contains(":empty")) + { + this.IsSubMenuOpen = !this.IsSubMenuOpen; + } } } } diff --git a/Perspex.Controls/Perspex.Controls.csproj b/Perspex.Controls/Perspex.Controls.csproj index 049e4e1903..763a0e5c58 100644 --- a/Perspex.Controls/Perspex.Controls.csproj +++ b/Perspex.Controls/Perspex.Controls.csproj @@ -37,6 +37,7 @@ + diff --git a/Perspex.Themes.Default/MenuItemStyle.cs b/Perspex.Themes.Default/MenuItemStyle.cs index 2cc0de8fd0..6ec245baef 100644 --- a/Perspex.Themes.Default/MenuItemStyle.cs +++ b/Perspex.Themes.Default/MenuItemStyle.cs @@ -45,6 +45,21 @@ namespace Perspex.Themes.Default new Setter(Border.BorderBrushProperty, new SolidColorBrush(0xff26a0da)), }, }, + new Style(x => x.OfType().Class(":empty").Template().Name("rightArrow")) + { + Setters = new[] + { + new Setter(Path.IsVisibleProperty, false), + }, + }, + new Style(x => x.OfType().PropertyEquals(MenuItem.IsSubMenuOpenProperty, true).Template().Name("root")) + { + Setters = new[] + { + new Setter(Border.BackgroundProperty, new SolidColorBrush(0x3d26a0da)), + new Setter(Border.BorderBrushProperty, new SolidColorBrush(0xff26a0da)), + }, + }, }); } @@ -71,7 +86,7 @@ namespace Perspex.Themes.Default (popup = new Popup { Name = "popup", - StaysOpen = false, + StaysOpen = true, [!!Popup.IsOpenProperty] = control[!!MenuItem.IsSubMenuOpenProperty], Child = new Border { @@ -160,10 +175,20 @@ namespace Perspex.Themes.Default [~ContentPresenter.MarginProperty] = control[~MenuItem.PaddingProperty], [Grid.ColumnProperty] = 2, }, + new Path + { + Name = "rightArrow", + Data = StreamGeometry.Parse("M0,0L4,3.5 0,7z"), + Fill = new SolidColorBrush(0xff212121), + Margin = new Thickness(10, 0, 0, 0), + UseLayoutRounding = false, + VerticalAlignment = VerticalAlignment.Center, + [Grid.ColumnProperty] = 3, + }, (popup = new Popup { Name = "popup", - StaysOpen = false, + StaysOpen = true, [!!Popup.IsOpenProperty] = control[!!MenuItem.IsSubMenuOpenProperty], Child = new Border { diff --git a/TestApplication/Program.cs b/TestApplication/Program.cs index fa467476a3..c2019547f7 100644 --- a/TestApplication/Program.cs +++ b/TestApplication/Program.cs @@ -151,6 +151,17 @@ namespace TestApplication new MenuItem { Header = "Save", + Items = new[] + { + new MenuItem + { + Header = "Sub Item 1", + }, + new MenuItem + { + Header = "Sub Item 2", + }, + } }, new MenuItem {