diff --git a/Perspex.Controls/INavigablePanel.cs b/Perspex.Controls/INavigablePanel.cs new file mode 100644 index 0000000000..e35af5e077 --- /dev/null +++ b/Perspex.Controls/INavigablePanel.cs @@ -0,0 +1,15 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2014 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Controls +{ + using Perspex.Input; + + public interface INavigablePanel + { + Control GetControl(FocusNavigationDirection direction, Control from); + } +} diff --git a/Perspex.Controls/Perspex.Controls.csproj b/Perspex.Controls/Perspex.Controls.csproj index 5ba608adf0..3cdd69bbbb 100644 --- a/Perspex.Controls/Perspex.Controls.csproj +++ b/Perspex.Controls/Perspex.Controls.csproj @@ -40,6 +40,7 @@ + diff --git a/Perspex.Controls/Primitives/SelectingItemsControl.cs b/Perspex.Controls/Primitives/SelectingItemsControl.cs index 63956b179a..ac8a35a6af 100644 --- a/Perspex.Controls/Primitives/SelectingItemsControl.cs +++ b/Perspex.Controls/Primitives/SelectingItemsControl.cs @@ -65,33 +65,25 @@ namespace Perspex.Controls.Primitives protected virtual void MoveSelection(FocusNavigationDirection direction) { - if (this.SelectedItem != null) + var panel = this.Presenter?.Panel as INavigablePanel; + var selected = this.SelectedItem; + var container = selected != null ? + this.ItemContainerGenerator.GetContainerForItem(selected) : + null; + + if (panel != null) { - int offset = 0; + var next = panel.GetControl(direction, container); - switch (direction) + if (next != null) { - case FocusNavigationDirection.Up: - case FocusNavigationDirection.Left: - offset = -1; - break; - case FocusNavigationDirection.Down: - case FocusNavigationDirection.Right: - offset = 1; - break; - } - - if (offset != 0) - { - var currentIndex = GetIndexOfItem(this.SelectedItem); - var index = currentIndex + offset; - - if (index >= 0 && index < this.Items.Cast().Count()) - { - this.SelectedItem = this.Items.Cast().ElementAt(index); - } + this.SelectedItem = this.ItemContainerGenerator.GetItemForContainer(next); } } + else + { + // TODO: Try doing a visual search? + } } protected override void OnKeyDown(KeyEventArgs e) diff --git a/Perspex.Controls/StackPanel.cs b/Perspex.Controls/StackPanel.cs index b53b98944e..9ca0b98c9d 100644 --- a/Perspex.Controls/StackPanel.cs +++ b/Perspex.Controls/StackPanel.cs @@ -7,10 +7,8 @@ namespace Perspex.Controls { using System; - using System.Collections.Generic; using System.Linq; - using System.Text; - using System.Threading.Tasks; + using Perspex.Input; public enum Orientation { @@ -18,7 +16,7 @@ namespace Perspex.Controls Horizontal, } - public class StackPanel : Panel + public class StackPanel : Panel, INavigablePanel { public static readonly PerspexProperty GapProperty = PerspexProperty.Register("Gap"); @@ -38,6 +36,49 @@ namespace Perspex.Controls set { this.SetValue(OrientationProperty, value); } } + Control INavigablePanel.GetControl(FocusNavigationDirection direction, Control from) + { + var horiz = this.Orientation == Orientation.Horizontal; + int index = this.Children.IndexOf(from); + + switch (direction) + { + case FocusNavigationDirection.First: + index = 0; + break; + case FocusNavigationDirection.Last: + index = this.Children.Count - 1; + break; + case FocusNavigationDirection.Next: + ++index; + break; + case FocusNavigationDirection.Previous: + ++index; + break; + case FocusNavigationDirection.Left: + index = horiz ? index - 1 : -1; + break; + case FocusNavigationDirection.Right: + index = horiz ? index + 1 : -1; + break; + case FocusNavigationDirection.Up: + index = horiz ? -1 : index - 1; + break; + case FocusNavigationDirection.Down: + index = horiz ? -1 : index + 1; + break; + } + + if (index >= 0 && index < this.Children.Count) + { + return this.Children[index]; + } + else + { + return null; + } + } + protected override Size MeasureOverride(Size availableSize) { double childAvailableWidth = double.PositiveInfinity;