diff --git a/Perspex.Controls/Menu.cs b/Perspex.Controls/Menu.cs new file mode 100644 index 0000000000..6fa9fbccbd --- /dev/null +++ b/Perspex.Controls/Menu.cs @@ -0,0 +1,19 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2015 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Controls +{ + public class Menu : ItemsControl + { + private static readonly ItemsPanelTemplate DefaultPanel = + new ItemsPanelTemplate(() => new StackPanel { Orientation = Orientation.Horizontal }); + + static Menu() + { + ItemsPanelProperty.OverrideDefaultValue(typeof(Menu), DefaultPanel); + } + } +} diff --git a/Perspex.Controls/MenuItem.cs b/Perspex.Controls/MenuItem.cs new file mode 100644 index 0000000000..2194444231 --- /dev/null +++ b/Perspex.Controls/MenuItem.cs @@ -0,0 +1,29 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2015 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Controls +{ + using Perspex.Controls.Primitives; + using Perspex.Input; + + public class MenuItem : HeaderedItemsControl + { + public static readonly PerspexProperty IsSubMenuOpenProperty = + PerspexProperty.Register("IsSubMenuOpen"); + + public bool IsSubMenuOpen + { + get { return this.GetValue(IsSubMenuOpenProperty); } + set { this.SetValue(IsSubMenuOpenProperty, value); } + } + + protected override void OnPointerPressed(PointerPressEventArgs e) + { + base.OnPointerPressed(e); + this.IsSubMenuOpen = !this.IsSubMenuOpen; + } + } +} diff --git a/Perspex.Controls/Perspex.Controls.csproj b/Perspex.Controls/Perspex.Controls.csproj index 8cdcd7de17..049e4e1903 100644 --- a/Perspex.Controls/Perspex.Controls.csproj +++ b/Perspex.Controls/Perspex.Controls.csproj @@ -37,6 +37,8 @@ + + diff --git a/Perspex.Themes.Default/DefaultTheme.cs b/Perspex.Themes.Default/DefaultTheme.cs index 717902161b..33dd3a1ce2 100644 --- a/Perspex.Themes.Default/DefaultTheme.cs +++ b/Perspex.Themes.Default/DefaultTheme.cs @@ -17,12 +17,14 @@ namespace Perspex.Themes.Default this.Add(new ButtonStyle()); this.Add(new CheckBoxStyle()); this.Add(new ContentControlStyle()); + this.Add(new DeckStyle()); this.Add(new DropDownStyle()); this.Add(new GridSplitterStyle()); this.Add(new ItemsControlStyle()); this.Add(new ListBoxStyle()); this.Add(new ListBoxItemStyle()); - this.Add(new DeckStyle()); + this.Add(new MenuStyle()); + this.Add(new MenuItemStyle()); this.Add(new PopupRootStyle()); this.Add(new RadioButtonStyle()); this.Add(new ScrollBarStyle()); diff --git a/Perspex.Themes.Default/MenuItemStyle.cs b/Perspex.Themes.Default/MenuItemStyle.cs new file mode 100644 index 0000000000..2ba94f2518 --- /dev/null +++ b/Perspex.Themes.Default/MenuItemStyle.cs @@ -0,0 +1,119 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2015 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Themes.Default +{ + using Perspex.Controls; + using Perspex.Controls.Presenters; + using Perspex.Controls.Shapes; + using Perspex.Input; + using Perspex.Layout; + using Perspex.Media; + using Perspex.Styling; + using System.Linq; + + public class MenuItemStyle : Styles + { + public MenuItemStyle() + { + this.AddRange(new[] + { + new Style(x => x.OfType()) + { + Setters = new[] + { + new Setter(MenuItem.BorderThicknessProperty, 1.0), + new Setter(MenuItem.PaddingProperty, new Thickness(6, 0)), + new Setter(MenuItem.TemplateProperty, ControlTemplate.Create(this.Template)), + }, + }, + new Style(x => x.OfType().Class(":pointerover").Template().Name("root")) + { + Setters = new[] + { + new Setter(Border.BackgroundProperty, new SolidColorBrush(0x3d26a0da)), + new Setter(Border.BorderBrushProperty, new SolidColorBrush(0xff26a0da)), + }, + } + }); + } + + private Control Template(MenuItem control) + { + Popup popup; + + var result = new Border + { + Name = "root", + [~Border.BackgroundProperty] = control[~MenuItem.BackgroundProperty], + [~Border.BorderBrushProperty] = control[~MenuItem.BorderBrushProperty], + [~Border.BorderThicknessProperty] = control[~MenuItem.BorderThicknessProperty], + Content = new Grid + { + ColumnDefinitions = new ColumnDefinitions + { + new ColumnDefinition(GridLength.Auto), + new ColumnDefinition(GridLength.Auto), + }, + Children = new Controls + { + //new ContentPresenter + //{ + // Name = "icon", + // [~ContentPresenter.ContentProperty] = control[~MenuItem.IconProperty], + // Width = 16, + // Height = 16, + // Margin = new Thickness(3), + // HorizontalAlignment = HorizontalAlignment.Center, + // VerticalAlignment = VerticalAlignment.Center, + //}, + new Path + { + Data = StreamGeometry.Parse("F1M10,1.2L4.7,9.1 4.5,9.1 0,5.2 1.3,3.5 4.3,6.1 8.3,0 10,1.2z"), + Margin = new Thickness(3), + IsVisible = false, + VerticalAlignment = VerticalAlignment.Center, + [~Path.FillProperty] = control[~MenuItem.ForegroundProperty], + }, + new ContentPresenter + { + [~ContentPresenter.ContentProperty] = control[~MenuItem.HeaderProperty], + [~ContentPresenter.MarginProperty] = control[~MenuItem.PaddingProperty], + [Grid.ColumnProperty] = 1, + }, + (popup = new Popup + { + Name = "popup", + StaysOpen = false, + [!!Popup.IsOpenProperty] = control[!!MenuItem.IsSubMenuOpenProperty], + Child = new Border + { + Background = new SolidColorBrush(0xfff0f0f0), + BorderBrush = new SolidColorBrush(0xff999999), + BorderThickness = 1, + Padding = new Thickness(2), + Content = new ScrollViewer + { + Content = new ItemsPresenter + { + Name = "itemsPresenter", + [~ItemsPresenter.ItemsProperty] = control[~Menu.ItemsProperty], + [~ItemsPresenter.ItemsPanelProperty] = control[~Menu.ItemsPanelProperty], + [KeyboardNavigation.TabNavigationProperty] = KeyboardNavigationMode.Cycle, + } + } + } + }) + }, + } + }; + + popup.PlacementTarget = result; + + return result; + } + } +} diff --git a/Perspex.Themes.Default/MenuStyle.cs b/Perspex.Themes.Default/MenuStyle.cs new file mode 100644 index 0000000000..64d39c9b24 --- /dev/null +++ b/Perspex.Themes.Default/MenuStyle.cs @@ -0,0 +1,47 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2015 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Themes.Default +{ + using Perspex.Controls; + using Perspex.Controls.Presenters; + using Perspex.Styling; + using System.Linq; + + public class MenuStyle : Styles + { + public MenuStyle() + { + this.AddRange(new[] + { + new Style(x => x.OfType()) + { + Setters = new[] + { + new Setter(Menu.TemplateProperty, ControlTemplate.Create(this.Template)), + }, + }, + }); + } + + private Control Template(Menu control) + { + return new Border + { + [~Border.BackgroundProperty] = control[~Menu.BackgroundProperty], + [~Border.BorderBrushProperty] = control[~Menu.BorderBrushProperty], + [~Border.BorderThicknessProperty] = control[~Menu.BorderThicknessProperty], + [~Border.PaddingProperty] = control[~Menu.PaddingProperty], + Content = new ItemsPresenter + { + Name = "itemsPresenter", + [~ItemsPresenter.ItemsProperty] = control[~Menu.ItemsProperty], + [~ItemsPresenter.ItemsPanelProperty] = control[~Menu.ItemsPanelProperty], + } + }; + } + } +} diff --git a/Perspex.Themes.Default/Perspex.Themes.Default.csproj b/Perspex.Themes.Default/Perspex.Themes.Default.csproj index 73837ab3b3..f2095987e8 100644 --- a/Perspex.Themes.Default/Perspex.Themes.Default.csproj +++ b/Perspex.Themes.Default/Perspex.Themes.Default.csproj @@ -71,6 +71,8 @@ + + diff --git a/TestApplication/Program.cs b/TestApplication/Program.cs index 00856c6ee9..9400b19ca7 100644 --- a/TestApplication/Program.cs +++ b/TestApplication/Program.cs @@ -129,11 +129,61 @@ namespace TestApplication }, RowDefinitions = new RowDefinitions { + new RowDefinition(GridLength.Auto), new RowDefinition(1, GridUnitType.Star), new RowDefinition(GridLength.Auto), }, Children = new Controls { + new Menu + { + Items = new[] + { + new MenuItem + { + Header = "_File", + Items = new[] + { + new MenuItem + { + Header = "_Open...", + }, + new MenuItem + { + Header = "_Save", + }, + new MenuItem + { + Header = "Save _As", + }, + new MenuItem + { + Header = "E_xit", + }, + } + }, + new MenuItem + { + Header = "_Edit", + Items = new[] + { + new MenuItem + { + Header = "Cu_t", + }, + new MenuItem + { + Header = "_Copy", + }, + new MenuItem + { + Header = "_Paste", + }, + } + } + }, + [Grid.ColumnSpanProperty] = 2, + }, new TabControl { Items = new[] @@ -146,13 +196,14 @@ namespace TestApplication AnimationsTab(), }, Transition = new PageSlide(TimeSpan.FromSeconds(0.25)), + [Grid.RowProperty] = 1, [Grid.ColumnSpanProperty] = 2, }, (fps = new TextBlock { HorizontalAlignment = HorizontalAlignment.Left, Margin = new Thickness(2), - [Grid.RowProperty] = 1, + [Grid.RowProperty] = 2, }), new TextBlock { @@ -160,7 +211,7 @@ namespace TestApplication HorizontalAlignment = HorizontalAlignment.Right, Margin = new Thickness(2), [Grid.ColumnProperty] = 1, - [Grid.RowProperty] = 1, + [Grid.RowProperty] = 2, }, } },