From bb112a998d42b31832b522e192823f862fcf4e87 Mon Sep 17 00:00:00 2001 From: Gadfly Date: Sat, 1 Feb 2025 23:41:54 +0800 Subject: [PATCH 1/2] feat: show CommitRelationTracking on CommitGraph (#940) - Add SHA property to the Dot class and assign commit SHA to anchor instances in the CommitGraph model. - Add constructor to initialize commit relation tracking with repository path and commit hash, enabling querying and displaying related refs while managing loading state. - Add pointer interaction handlers to the `CommitGraph` class for displaying commit details on click, updating cursor on hover, and resetting cursor on exit. --- src/Models/CommitGraph.cs | 3 +- src/Views/CommitRelationTracking.axaml.cs | 17 +++++++ src/Views/Histories.axaml | 2 +- src/Views/Histories.axaml.cs | 57 +++++++++++++++++++++++ 4 files changed, 77 insertions(+), 2 deletions(-) diff --git a/src/Models/CommitGraph.cs b/src/Models/CommitGraph.cs index 772097513..96e640af6 100644 --- a/src/Models/CommitGraph.cs +++ b/src/Models/CommitGraph.cs @@ -54,6 +54,7 @@ public class Dot public Point Center; public int Color; public bool IsMerged; + public string SHA; } public List Paths { get; } = []; @@ -149,7 +150,7 @@ public static CommitGraph Parse(List commits, bool firstParentOnlyEnable // Calculate link position of this commit. var position = new Point(major?.LastX ?? offsetX, offsetY); var dotColor = major?.Path.Color ?? 0; - var anchor = new Dot() { Center = position, Color = dotColor, IsMerged = isMerged }; + var anchor = new Dot() { Center = position, Color = dotColor, IsMerged = isMerged, SHA = commit.SHA }; if (commit.IsCurrentHead) anchor.Type = DotType.Head; else if (commit.Parents.Count > 1) diff --git a/src/Views/CommitRelationTracking.axaml.cs b/src/Views/CommitRelationTracking.axaml.cs index 1e436552c..81502fbbe 100644 --- a/src/Views/CommitRelationTracking.axaml.cs +++ b/src/Views/CommitRelationTracking.axaml.cs @@ -28,5 +28,22 @@ public CommitRelationTracking(ViewModels.CommitDetail detail) }); }); } + + public CommitRelationTracking(string repoPath, string commitHash) + { + InitializeComponent(); + + LoadingIcon.IsVisible = true; + + Task.Run(() => + { + var containsIn = new Commands.QueryRefsContainsCommit(repoPath, commitHash).Result(); + Dispatcher.UIThread.Invoke(() => + { + Container.ItemsSource = containsIn; + LoadingIcon.IsVisible = false; + }); + }); + } } } diff --git a/src/Views/Histories.axaml b/src/Views/Histories.axaml index 5cde532f9..31e9c10d5 100644 --- a/src/Views/Histories.axaml +++ b/src/Views/Histories.axaml @@ -207,7 +207,7 @@ DotBrush="{DynamicResource Brush.Contents}" OnlyHighlightCurrentBranch="{Binding $parent[v:Histories].OnlyHighlightCurrentBranch}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" - IsHitTestVisible="False" + IsHitTestVisible="True" ClipToBounds="True"/> diff --git a/src/Views/Histories.axaml.cs b/src/Views/Histories.axaml.cs index 8b5142add..00f45ce77 100644 --- a/src/Views/Histories.axaml.cs +++ b/src/Views/Histories.axaml.cs @@ -520,6 +520,13 @@ static CommitGraph() AffectsRender(GraphProperty, DotBrushProperty, OnlyHighlightCurrentBranchProperty); } + public CommitGraph() + { + PointerPressed += OnPointerPressed; + PointerMoved += OnPointerMoved; + PointerExited += OnPointerExited; + } + public override void Render(DrawingContext context) { base.Render(context); @@ -705,6 +712,56 @@ private void DrawAnchors(DrawingContext context, Models.CommitGraph graph, doubl } } } + + private void OnPointerPressed(object sender, PointerPressedEventArgs e) + { + var point = e.GetPosition(this); + var dot = FindDotAtPosition(point); + var repoView = this.FindAncestorOfType(); + var repoPath = (repoView?.DataContext as ViewModels.Repository)?.FullPath; + if (dot == null || string.IsNullOrEmpty(repoPath)) + return; + + var tracking = new CommitRelationTracking(repoPath, dot.SHA); + var flyout = new Flyout { Content = tracking }; + flyout.ShowAt(this, true); + } + + private void OnPointerMoved(object sender, PointerEventArgs e) + { + var point = e.GetPosition(this); + var dot = FindDotAtPosition(point); + Cursor = dot != null ? new Cursor(StandardCursorType.Hand) : new Cursor(StandardCursorType.Arrow); + } + + private void OnPointerExited(object sender, PointerEventArgs e) + { + Cursor = new Cursor(StandardCursorType.Arrow); + } + + private Models.CommitGraph.Dot FindDotAtPosition(Point point) + { + var graph = Graph; + if (graph == null) + return null; + + // get scroll offset + var histories = this.FindAncestorOfType(); + var scrollOffset = histories?.CommitListContainer.Scroll?.Offset.Y ?? 0; + + // adjust point + var adjustedPoint = new Point(point.X, point.Y + scrollOffset); + + foreach (var dot in graph.Dots) + { + var distance = Math.Sqrt(Math.Pow(dot.Center.X - adjustedPoint.X, 2) + Math.Pow(dot.Center.Y - adjustedPoint.Y, 2)); + if (distance <= 6) + { + return dot; + } + } + return null; + } } public partial class Histories : UserControl From b9b5ee621f7e14a7bb64e96ae7617a8f6369fa9f Mon Sep 17 00:00:00 2001 From: Gadfly Date: Thu, 6 Feb 2025 17:13:56 +0800 Subject: [PATCH 2/2] refactor: Optimize ancestor lookups and dot search logic --- src/Views/Histories.axaml.cs | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/Views/Histories.axaml.cs b/src/Views/Histories.axaml.cs index 00f45ce77..fab49a94e 100644 --- a/src/Views/Histories.axaml.cs +++ b/src/Views/Histories.axaml.cs @@ -535,16 +535,15 @@ public override void Render(DrawingContext context) if (graph == null) return; - var histories = this.FindAncestorOfType(); - if (histories == null) - return; + _repoView = this.FindAncestorOfType(); + _histories = this.FindAncestorOfType(); - var list = histories.CommitListContainer; + var list = _histories?.CommitListContainer; if (list == null) return; // Calculate drawing area. - double width = Bounds.Width - 273 - histories.AuthorNameColumnWidth.Value; + double width = Bounds.Width - 273 - _histories.AuthorNameColumnWidth.Value; double height = Bounds.Height; double startY = list.Scroll?.Offset.Y ?? 0; double endY = startY + height + 28; @@ -717,8 +716,7 @@ private void OnPointerPressed(object sender, PointerPressedEventArgs e) { var point = e.GetPosition(this); var dot = FindDotAtPosition(point); - var repoView = this.FindAncestorOfType(); - var repoPath = (repoView?.DataContext as ViewModels.Repository)?.FullPath; + var repoPath = (_repoView?.DataContext as ViewModels.Repository)?.FullPath; if (dot == null || string.IsNullOrEmpty(repoPath)) return; @@ -746,22 +744,32 @@ private Models.CommitGraph.Dot FindDotAtPosition(Point point) return null; // get scroll offset - var histories = this.FindAncestorOfType(); - var scrollOffset = histories?.CommitListContainer.Scroll?.Offset.Y ?? 0; + var scrollOffset = _histories?.CommitListContainer.Scroll?.Offset.Y ?? 0; // adjust point var adjustedPoint = new Point(point.X, point.Y + scrollOffset); + var searchRadius = 9.0; foreach (var dot in graph.Dots) { + if (!(Math.Abs(dot.Center.X - adjustedPoint.X) <= searchRadius) || + !(Math.Abs(dot.Center.Y - adjustedPoint.Y) <= searchRadius)) + { + continue; + } + var distance = Math.Sqrt(Math.Pow(dot.Center.X - adjustedPoint.X, 2) + Math.Pow(dot.Center.Y - adjustedPoint.Y, 2)); - if (distance <= 6) + if (distance <= searchRadius) { return dot; } } + return null; } + + private Histories _histories; + private Repository _repoView; } public partial class Histories : UserControl