Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 64 additions & 5 deletions src/Views/ChangeCollectionView.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Media;
using Avalonia.Threading;
using Avalonia.VisualTree;

namespace SourceGit.Views
Expand Down Expand Up @@ -35,19 +36,77 @@ public class ChangeCollectionContainer : ListBox

protected override void OnKeyDown(KeyEventArgs e)
{
if (SelectedItems is [ViewModels.ChangeTreeNode node])
if (e.KeyModifiers == KeyModifiers.None &&
(e.Key == Key.Left || e.Key == Key.Right) &&
SelectedItems is [ViewModels.ChangeTreeNode node] &&
this.FindAncestorOfType<ChangeCollectionView>() is { Content: ViewModels.ChangeCollectionAsTree tree } view)
{
if (((e.Key == Key.Left && node.IsExpanded) || (e.Key == Key.Right && !node.IsExpanded)) &&
e.KeyModifiers == KeyModifiers.None)
if (e.Key == Key.Left)
{
this.FindAncestorOfType<ChangeCollectionView>()?.ToggleNodeIsExpanded(node);
e.Handled = true;
if (node.IsFolder && node.IsExpanded)
{
view.ToggleNodeIsExpanded(node);
}
else
{
var parent = FindParentRow(tree.Rows, node);
if (parent != null)
MoveSelectionTo(parent);
}
}
else
{
if (node.IsFolder && !node.IsExpanded)
{
view.ToggleNodeIsExpanded(node);
}
else if (node.IsFolder)
{
var idx = tree.Rows.IndexOf(node);
if (idx >= 0 && idx + 1 < tree.Rows.Count)
{
var child = tree.Rows[idx + 1];
if (child.Depth == node.Depth + 1)
MoveSelectionTo(child);
}
}
}

e.Handled = true;
}

if (!e.Handled && e.Key != Key.Space && e.Key != Key.Enter)
base.OnKeyDown(e);
}

private void MoveSelectionTo(ViewModels.ChangeTreeNode target)
{
SelectedItem = target;
ScrollIntoView(target);
if (ContainerFromItem(target) is Control container)
container.Focus();
else
Dispatcher.UIThread.Post(() => (ContainerFromItem(target) as Control)?.Focus(), DispatcherPriority.Loaded);
}

private static ViewModels.ChangeTreeNode FindParentRow(IList<ViewModels.ChangeTreeNode> rows, ViewModels.ChangeTreeNode node)
{
if (node.Depth == 0)
return null;

var idx = rows.IndexOf(node);
if (idx <= 0)
return null;

var parentDepth = node.Depth - 1;
for (int i = idx - 1; i >= 0; i--)
{
if (rows[i].Depth == parentDepth)
return rows[i];
}

return null;
}
}

public partial class ChangeCollectionView : UserControl
Expand Down
70 changes: 64 additions & 6 deletions src/Views/RevisionFileTreeView.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Platform.Storage;
using Avalonia.Threading;
using Avalonia.VisualTree;

namespace SourceGit.Views
Expand Down Expand Up @@ -123,13 +124,41 @@ protected override async void OnKeyDown(KeyEventArgs e)

if (SelectedItem is ViewModels.RevisionFileTreeNode node)
{
if (node.IsFolder &&
e.KeyModifiers == KeyModifiers.None &&
(node.IsExpanded && e.Key == Key.Left) || (!node.IsExpanded && e.Key == Key.Right))
if (e.KeyModifiers == KeyModifiers.None &&
(e.Key == Key.Left || e.Key == Key.Right) &&
this.FindAncestorOfType<RevisionFileTreeView>() is { } view)
{
var tree = this.FindAncestorOfType<RevisionFileTreeView>();
if (tree != null)
await tree.ToggleNodeIsExpandedAsync(node);
if (e.Key == Key.Left)
{
if (node.IsFolder && node.IsExpanded)
{
await view.ToggleNodeIsExpandedAsync(node);
}
else
{
var parent = FindParentRow(view.Rows, node);
if (parent != null)
MoveSelectionTo(parent);
}
}
else
{
if (node.IsFolder && !node.IsExpanded)
{
await view.ToggleNodeIsExpandedAsync(node);
}
else if (node.IsFolder)
{
var idx = view.Rows.IndexOf(node);
if (idx >= 0 && idx + 1 < view.Rows.Count)
{
var child = view.Rows[idx + 1];
if (child.Depth == node.Depth + 1)
MoveSelectionTo(child);
}
}
}

e.Handled = true;
}
else if (e.Key == Key.C &&
Expand Down Expand Up @@ -182,6 +211,35 @@ protected override async void OnKeyDown(KeyEventArgs e)
if (!e.Handled)
base.OnKeyDown(e);
}

private void MoveSelectionTo(ViewModels.RevisionFileTreeNode target)
{
SelectedItem = target;
ScrollIntoView(target);
if (ContainerFromItem(target) is Control container)
container.Focus();
else
Dispatcher.UIThread.Post(() => (ContainerFromItem(target) as Control)?.Focus(), DispatcherPriority.Loaded);
}

private static ViewModels.RevisionFileTreeNode FindParentRow(IList<ViewModels.RevisionFileTreeNode> rows, ViewModels.RevisionFileTreeNode node)
{
if (node.Depth == 0)
return null;

var idx = rows.IndexOf(node);
if (idx <= 0)
return null;

var parentDepth = node.Depth - 1;
for (int i = idx - 1; i >= 0; i--)
{
if (rows[i].Depth == parentDepth)
return rows[i];
}

return null;
}
}

public partial class RevisionFileTreeView : UserControl
Expand Down