refactor: only redraw commit graph when it is necessary

Signed-off-by: leo <longshuang@msn.cn>
This commit is contained in:
leo
2025-06-30 17:12:26 +08:00
parent 09fadea152
commit d1cc83648b
4 changed files with 79 additions and 45 deletions

View File

@@ -6,6 +6,13 @@ using Avalonia.Media;
namespace SourceGit.Models
{
public record CommitGraphLayout(double startY, double clipWidth, double rowHeight)
{
public double StartY { get; set; } = startY;
public double ClipWidth { get; set; } = clipWidth;
public double RowHeight { get; set; } = rowHeight;
}
public class CommitGraph
{
public static List<Pen> Pens { get; } = [];

View File

@@ -1,8 +1,6 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Media;
using Avalonia.VisualTree;
namespace SourceGit.Views
{
@@ -35,57 +33,39 @@ namespace SourceGit.Views
set => SetValue(OnlyHighlightCurrentBranchProperty, value);
}
public static readonly StyledProperty<Models.CommitGraphLayout> LayoutProperty =
AvaloniaProperty.Register<CommitGraph, Models.CommitGraphLayout>(nameof(Layout));
public Models.CommitGraphLayout Layout
{
get => GetValue(LayoutProperty);
set => SetValue(LayoutProperty, value);
}
static CommitGraph()
{
AffectsRender<CommitGraph>(GraphProperty, DotBrushProperty, OnlyHighlightCurrentBranchProperty);
AffectsRender<CommitGraph>(
GraphProperty,
DotBrushProperty,
OnlyHighlightCurrentBranchProperty,
LayoutProperty);
}
public override void Render(DrawingContext context)
{
base.Render(context);
var graph = Graph;
if (graph == null)
if (Graph is not { } graph || Layout is not { } layout)
return;
var histories = this.FindAncestorOfType<Histories>();
if (histories == null)
return;
var startY = layout.StartY;
var clipWidth = layout.ClipWidth;
var clipHeight = Bounds.Height;
var rowHeight = layout.RowHeight;
var endY = startY + clipHeight + 28;
var grid = histories.CommitListContainer;
if (grid == null)
return;
var rowsPresenter = grid.FindDescendantOfType<DataGridRowsPresenter>();
if (rowsPresenter == null)
return;
double rowHeight = grid.RowHeight;
double startY = 0;
foreach (var child in rowsPresenter.Children)
{
var row = child as DataGridRow;
if (row.IsVisible)
{
if (rowHeight != row.Bounds.Height)
rowHeight = row.Bounds.Height;
if (row.Bounds.Top <= 0 && row.Bounds.Top > -rowHeight)
{
var test = rowHeight * row.Index - row.Bounds.Top;
if (startY < test)
startY = test;
}
}
}
var headersHeight = grid.ColumnHeaderHeight;
var width = histories.CommitListContainer.Columns[0].ActualWidth;
var height = Bounds.Height - headersHeight;
var endY = startY + height + 28;
using (context.PushClip(new Rect(0, headersHeight, width, height)))
using (context.PushTransform(Matrix.CreateTranslation(0, headersHeight - startY)))
using (context.PushClip(new Rect(0, 0, clipWidth, clipHeight)))
using (context.PushTransform(Matrix.CreateTranslation(0, -startY)))
{
DrawCurves(context, graph, startY, endY, rowHeight);
DrawAnchors(context, graph, startY, endY, rowHeight);

View File

@@ -226,6 +226,7 @@
</DataGrid>
<v:CommitGraph x:Name="CommitGraph"
Margin="0,24,0,0"
Graph="{Binding Graph}"
DotBrush="{DynamicResource Brush.Contents}"
OnlyHighlightCurrentBranch="{Binding $parent[v:Histories].OnlyHighlightCurrentBranch}"

View File

@@ -4,6 +4,7 @@ using System.Text;
using Avalonia;
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.VisualTree;
@@ -137,14 +138,55 @@ namespace SourceGit.Views
private void OnCommitListLoaded(object sender, RoutedEventArgs e)
{
if (CommitListContainer is { SelectedItems.Count: 1 } dataGrid)
var dataGrid = CommitListContainer;
var rowsPresenter = dataGrid.FindDescendantOfType<DataGridRowsPresenter>();
if (rowsPresenter is { Children: { Count: > 0 } rows })
CommitGraph.Layout = new(0, dataGrid.Columns[0].ActualWidth, rows[0].Bounds.Height);
if (dataGrid.SelectedItems.Count == 1)
dataGrid.ScrollIntoView(dataGrid.SelectedItem, null);
}
private void OnCommitListLayoutUpdated(object _1, EventArgs _2)
{
if (IsLoaded)
CommitGraph.InvalidateVisual();
if (!IsLoaded)
return;
var dataGrid = CommitListContainer;
var rowsPresenter = dataGrid.FindDescendantOfType<DataGridRowsPresenter>();
if (rowsPresenter == null)
return;
double rowHeight = dataGrid.RowHeight;
double startY = 0;
foreach (var child in rowsPresenter.Children)
{
var row = child as DataGridRow;
if (row.IsVisible)
{
if (rowHeight != row.Bounds.Height)
rowHeight = row.Bounds.Height;
if (row.Bounds.Top <= 0 && row.Bounds.Top > -rowHeight)
{
var test = rowHeight * row.Index - row.Bounds.Top;
if (startY < test)
startY = test;
}
}
}
var clipWidth = dataGrid.Columns[0].ActualWidth;
if (_lastGraphStartY != startY ||
_lastGraphClipWidth != clipWidth ||
_lastGraphRowHeight != rowHeight)
{
_lastGraphStartY = startY;
_lastGraphClipWidth = clipWidth;
_lastGraphRowHeight = rowHeight;
CommitGraph.Layout = new(startY, clipWidth, rowHeight);
}
}
private void OnCommitListSelectionChanged(object _, SelectionChangedEventArgs e)
@@ -228,5 +270,9 @@ namespace SourceGit.Views
histories.CheckoutBranchByCommit(c);
}
}
private double _lastGraphStartY = 0;
private double _lastGraphClipWidth = 0;
private double _lastGraphRowHeight = 0;
}
}