diff --git a/Perspex.Controls/Deck.cs b/Perspex.Controls/Deck.cs new file mode 100644 index 0000000000..71497eac31 --- /dev/null +++ b/Perspex.Controls/Deck.cs @@ -0,0 +1,44 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2015 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Controls +{ + using System.Collections; + using Perspex.Controls.Generators; + using Perspex.Controls.Primitives; + using Perspex.Controls.Utils; + + /// + /// A selecting items control that displays a single item that fills the control. + /// + public class Deck : SelectingItemsControl + { + private static readonly ItemsPanelTemplate PanelTemplate = + new ItemsPanelTemplate(() => new Panel()); + + static Deck() + { + ItemsPanelProperty.OverrideDefaultValue(typeof(Deck), PanelTemplate); + } + + protected override ItemContainerGenerator CreateItemContainerGenerator() + { + return new TypedItemContainerGenerator(this); + } + + protected override void ItemsChanged(IEnumerable oldValue, IEnumerable newValue) + { + base.ItemsChanged(oldValue, newValue); + + var items = this.Items; + + if (items != null && items.Count() > 0) + { + this.SelectedIndex = 0; + } + } + } +} diff --git a/Perspex.Controls/DeckItem.cs b/Perspex.Controls/DeckItem.cs new file mode 100644 index 0000000000..4def87b526 --- /dev/null +++ b/Perspex.Controls/DeckItem.cs @@ -0,0 +1,25 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2015 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Controls +{ + public class DeckItem : ContentControl, ISelectable + { + public static readonly PerspexProperty IsSelectedProperty = + PerspexProperty.Register("IsSelected"); + + static DeckItem() + { + Control.PseudoClass(IsSelectedProperty, ":selected"); + } + + public bool IsSelected + { + get { return this.GetValue(IsSelectedProperty); } + set { this.SetValue(IsSelectedProperty, value); } + } + } +} diff --git a/Perspex.Controls/Perspex.Controls.csproj b/Perspex.Controls/Perspex.Controls.csproj index 360d044f75..a21f9cc112 100644 --- a/Perspex.Controls/Perspex.Controls.csproj +++ b/Perspex.Controls/Perspex.Controls.csproj @@ -41,6 +41,8 @@ + + diff --git a/Perspex.Themes.Default/DeckItemStyle.cs b/Perspex.Themes.Default/DeckItemStyle.cs new file mode 100644 index 0000000000..c60382f374 --- /dev/null +++ b/Perspex.Themes.Default/DeckItemStyle.cs @@ -0,0 +1,38 @@ +// ----------------------------------------------------------------------- +// +// 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 DeckItemStyle : Styles + { + public DeckItemStyle() + { + this.AddRange(new[] + { + new Style(x => x.OfType()) + { + Setters = new[] + { + new Setter(DeckItem.TemplateProperty, ControlTemplate.Create(this.Template)), + }, + }, + }); + } + + private Control Template(DeckItem control) + { + return new ContentPresenter + { + [~ContentPresenter.ContentProperty] = control[~DeckItem.ContentProperty], + }; + } + } +} diff --git a/Perspex.Themes.Default/DeckStyle.cs b/Perspex.Themes.Default/DeckStyle.cs new file mode 100644 index 0000000000..07494599e3 --- /dev/null +++ b/Perspex.Themes.Default/DeckStyle.cs @@ -0,0 +1,54 @@ +// ----------------------------------------------------------------------- +// +// 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 DeckStyle : Styles + { + public DeckStyle() + { + this.AddRange(new[] + { + new Style(x => x.OfType()) + { + Setters = new[] + { + new Setter(Deck.TemplateProperty, ControlTemplate.Create(this.Template)), + }, + }, + new Style(x => x.OfType().Descendent().Is()) + { + Setters = new[] + { + new Setter(Control.IsVisibleProperty, false), + }, + }, + new Style(x => x.OfType().Descendent().Is().Class(":selected")) + { + Setters = new[] + { + new Setter(Control.IsVisibleProperty, true), + }, + } + }); + } + + private Control Template(Deck control) + { + return new ItemsPresenter + { + Id = "itemsPresenter", + [~ItemsPresenter.ItemsProperty] = control[~Deck.ItemsProperty], + [~ItemsPresenter.ItemsPanelProperty] = control[~Deck.ItemsPanelProperty], + }; + } + } +} diff --git a/Perspex.Themes.Default/DefaultTheme.cs b/Perspex.Themes.Default/DefaultTheme.cs index d85bef9421..59d3b208e3 100644 --- a/Perspex.Themes.Default/DefaultTheme.cs +++ b/Perspex.Themes.Default/DefaultTheme.cs @@ -22,6 +22,8 @@ namespace Perspex.Themes.Default this.Add(new ItemsControlStyle()); this.Add(new ListBoxStyle()); this.Add(new ListBoxItemStyle()); + this.Add(new DeckStyle()); + this.Add(new DeckItemStyle()); this.Add(new PopupRootStyle()); this.Add(new RadioButtonStyle()); this.Add(new ScrollBarStyle()); diff --git a/Perspex.Themes.Default/ListBoxItemStyle.cs b/Perspex.Themes.Default/ListBoxItemStyle.cs index 974b455e86..d87f93e476 100644 --- a/Perspex.Themes.Default/ListBoxItemStyle.cs +++ b/Perspex.Themes.Default/ListBoxItemStyle.cs @@ -6,14 +6,11 @@ namespace Perspex.Themes.Default { - using System.Linq; using Perspex.Controls; - using Perspex.Layout; + using Perspex.Controls.Presenters; using Perspex.Media; - using Perspex.Controls.Shapes; using Perspex.Styling; - using Perspex.Controls.Presenters; - using Perspex.Controls.Primitives; + using System.Linq; public class ListBoxItemStyle : Styles { diff --git a/Perspex.Themes.Default/Perspex.Themes.Default.csproj b/Perspex.Themes.Default/Perspex.Themes.Default.csproj index af2f6cdb10..ec57ba1004 100644 --- a/Perspex.Themes.Default/Perspex.Themes.Default.csproj +++ b/Perspex.Themes.Default/Perspex.Themes.Default.csproj @@ -72,6 +72,8 @@ + + diff --git a/TestApplication/Program.cs b/TestApplication/Program.cs index c85160351b..82552bd2b9 100644 --- a/TestApplication/Program.cs +++ b/TestApplication/Program.cs @@ -106,8 +106,9 @@ namespace TestApplication static void Main(string[] args) { - //LogManager.Enable(new TestLogger()); + LogManager.Enable(new TestLogger()); //LogManager.Instance.LogLayoutMessages = true; + LogManager.Instance.LogPropertyMessages = true; // The version of ReactiveUI currently included is for WPF and so expects a WPF // dispatcher. This makes sure it's initialized. @@ -176,14 +177,14 @@ namespace TestApplication DevTools.Attach(window); - var renderer = ((IRenderRoot)window).Renderer; - var last = renderer.RenderCount; - DispatcherTimer.Run(() => - { - fps.Text = "FPS: " + (renderer.RenderCount - last); - last = renderer.RenderCount; - return true; - }, TimeSpan.FromSeconds(1)); + //var renderer = ((IRenderRoot)window).Renderer; + //var last = renderer.RenderCount; + //DispatcherTimer.Run(() => + //{ + // fps.Text = "FPS: " + (renderer.RenderCount - last); + // last = renderer.RenderCount; + // return true; + //}, TimeSpan.FromSeconds(1)); window.Show(); Application.Current.Run(window); @@ -383,6 +384,8 @@ namespace TestApplication private static TabItem ListsTab() { + ListBox listBox; + return new TabItem { Header = "Lists", @@ -411,10 +414,16 @@ namespace TestApplication Id = "treeView", Items = treeData, }, - new ListBox + (listBox = new ListBox { Items = listBoxData, + SelectedIndex = 0, MaxHeight = 300, + }), + new Deck + { + Items = listBoxData, + [!Deck.SelectedItemProperty] = listBox[!ListBox.SelectedItemProperty], }, new DropDown { @@ -565,20 +574,20 @@ namespace TestApplication } }; - var start = Animate.Stopwatch.Elapsed; - var degrees = Animate.Timer - .Select(x => - { - var elapsed = (x - start).TotalSeconds; - var cycles = elapsed / 4; - var progress = cycles % 1; - return 360.0 * progress; - }); - - border1.RenderTransform.Bind( - RotateTransform.AngleProperty, - degrees, - BindingPriority.Animation); + //var start = Animate.Stopwatch.Elapsed; + //var degrees = Animate.Timer + // .Select(x => + // { + // var elapsed = (x - start).TotalSeconds; + // var cycles = elapsed / 4; + // var progress = cycles % 1; + // return 360.0 * progress; + // }); + + //border1.RenderTransform.Bind( + // RotateTransform.AngleProperty, + // degrees, + // BindingPriority.Animation); return result; } diff --git a/Tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs b/Tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs index 63954d9569..0d280f30a0 100644 --- a/Tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs +++ b/Tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs @@ -14,6 +14,24 @@ namespace Perspex.Controls.Primitives.UnitTests public class SelectingItemsControlTests { + [Fact] + public void SelectedIndex_Should_Initially_Be_Minus_1() + { + var items = new[] + { + new Item(), + new Item(), + }; + + var target = new Target + { + Items = items, + Template = this.Template(), + }; + + Assert.Equal(-1, target.SelectedIndex); + } + [Fact] public void Item_IsSelected_Should_Initially_Be_False() {