diff --git a/src/ViewModels/Welcome.cs b/src/ViewModels/Welcome.cs index 8d6c423e..97eb4448 100644 --- a/src/ViewModels/Welcome.cs +++ b/src/ViewModels/Welcome.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Avalonia.Collections; using Avalonia.Controls; @@ -76,6 +77,30 @@ namespace SourceGit.ViewModels Preference.Instance.MoveNode(from, to); } + public RepositoryNode GetPrevVisible(RepositoryNode node) + { + var visibleRows = new List(); + CollectVisibleRows(visibleRows, RepositoryNodes); + + var idx = visibleRows.IndexOf(node); + if (idx <= 1) + return null; + + return visibleRows[idx - 1]; + } + + public RepositoryNode GetNextVisible(RepositoryNode node) + { + var visibleRows = new List(); + CollectVisibleRows(visibleRows, RepositoryNodes); + + var idx = visibleRows.IndexOf(node); + if (idx < 0 || idx >= visibleRows.Count - 1) + return null; + + return visibleRows[idx + 1]; + } + public ContextMenu CreateContextMenu(RepositoryNode node) { var menu = new ContextMenu(); @@ -212,6 +237,20 @@ namespace SourceGit.ViewModels } } + private void CollectVisibleRows(List visible, AvaloniaList collection) + { + foreach (var node in collection) + { + if (node.IsVisible) + { + visible.Add(node); + + if (!node.IsRepository) + CollectVisibleRows(visible, node.SubNodes); + } + } + } + private static Welcome _instance = new Welcome(); private string _searchFilter = string.Empty; } diff --git a/src/Views/Welcome.axaml b/src/Views/Welcome.axaml index 6e0e1d94..ecb8c855 100644 --- a/src/Views/Welcome.axaml +++ b/src/Views/Welcome.axaml @@ -42,6 +42,7 @@ ScrollViewer.VerticalScrollBarVisibility="Auto" Loaded="SetupTreeViewDragAndDrop" LostFocus="OnTreeViewLostFocus" + SelectionChanged="OnTreeViewSelectionChanged" KeyDown="OnTreeViewKeyDown"> diff --git a/src/Views/Welcome.axaml.cs b/src/Views/Welcome.axaml.cs index 2cb08021..7f0630f3 100644 --- a/src/Views/Welcome.axaml.cs +++ b/src/Views/Welcome.axaml.cs @@ -48,7 +48,6 @@ namespace SourceGit.Views if (c is TreeViewItem { IsVisible: true } item) { ReposTree.SelectedItem = item.DataContext; - item.Focus(); break; } } @@ -59,13 +58,41 @@ namespace SourceGit.Views private void OnTreeViewKeyDown(object sender, KeyEventArgs e) { - if (e.Key == Key.Space && ReposTree.SelectedItem is ViewModels.RepositoryNode { IsRepository: true } node) + if (ReposTree.SelectedItem is ViewModels.RepositoryNode node) { - var parent = this.FindAncestorOfType(); - if (parent?.DataContext is ViewModels.Launcher launcher) - launcher.OpenRepositoryInTab(node, null); + if (e.Key == Key.Space && node.IsRepository) + { + var parent = this.FindAncestorOfType(); + if (parent?.DataContext is ViewModels.Launcher launcher) + launcher.OpenRepositoryInTab(node, null); - e.Handled = true; + e.Handled = true; + } + else if (e.Key == Key.Down) + { + var next = ViewModels.Welcome.Instance.GetNextVisible(node); + if (next != null) + ReposTree.SelectedItem = next; + + e.Handled = true; + } + else if (e.Key == Key.Up) + { + var prev = ViewModels.Welcome.Instance.GetPrevVisible(node); + if (prev != null) + ReposTree.SelectedItem = prev; + + e.Handled = true; + } + } + } + + private void OnTreeViewSelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (ReposTree.SelectedItem is ViewModels.RepositoryNode node) + { + var item = FindTreeViewItemByNode(node, ReposTree); + item?.Focus(NavigationMethod.Directional); } } @@ -264,6 +291,26 @@ namespace SourceGit.Views launcher?.OpenRepositoryInTab(node, launcher.ActivePage); } + private TreeViewItem FindTreeViewItemByNode(ViewModels.RepositoryNode node, ItemsControl container) + { + var items = container.GetRealizedContainers(); + + foreach (var item in items) + { + if (item is TreeViewItem { DataContext: ViewModels.RepositoryNode test } treeViewItem) + { + if (test == node) + return treeViewItem; + + var child = FindTreeViewItemByNode(node, treeViewItem); + if (child != null) + return child; + } + } + + return null; + } + private bool _pressedTreeNode = false; private Point _pressedTreeNodePosition = new Point(); private bool _startDragTreeNode = false;