fix: offset of commit graph does not look quite right (#1287)

This is because that when using `VirtualizingStackPanel`, the `Bounds.Height` of `ListBoxItem` may not be the same with its `Height` setted in axaml.

Signed-off-by: leo <longshuang@msn.cn>
This commit is contained in:
leo 2025-05-08 12:22:23 +08:00
parent 6df38ad970
commit 832fcd7487
No known key found for this signature in database
3 changed files with 52 additions and 30 deletions

View file

@ -64,8 +64,8 @@ namespace SourceGit.Models
{ {
const double unitWidth = 12; const double unitWidth = 12;
const double halfWidth = 6; const double halfWidth = 6;
const double unitHeight = 28; const double unitHeight = 1;
const double halfHeight = 14; const double halfHeight = 0.5;
var temp = new CommitGraph(); var temp = new CommitGraph();
var unsolved = new List<PathHelper>(); var unsolved = new List<PathHelper>();

View file

@ -56,22 +56,33 @@ namespace SourceGit.Views
return; return;
// Calculate drawing area. // Calculate drawing area.
double width = Bounds.Width - 273 - histories.AuthorNameColumnWidth.Value; var width = Bounds.Width - 273 - histories.AuthorNameColumnWidth.Value;
double height = Bounds.Height; var height = Bounds.Height;
double startY = list.Scroll?.Offset.Y ?? 0;
double endY = startY + height + 28; // Calculate row height
var container = list.ItemsPanelRoot as VirtualizingStackPanel;
if (container == null)
return;
var item = list.ContainerFromIndex(container.FirstRealizedIndex);
if (item == null)
return;
var rowHeight = item.Bounds.Height;
var startY = container.FirstRealizedIndex * rowHeight - item.TranslatePoint(new Point(0, 0), list).Value!.Y;
var endY = startY + height + 28;
// Apply scroll offset and clip. // Apply scroll offset and clip.
using (context.PushClip(new Rect(0, 0, width, height))) using (context.PushClip(new Rect(0, 0, width, height)))
using (context.PushTransform(Matrix.CreateTranslation(0, -startY))) using (context.PushTransform(Matrix.CreateTranslation(0, -startY)))
{ {
// Draw contents // Draw contents
DrawCurves(context, graph, startY, endY); DrawCurves(context, graph, startY, endY, rowHeight);
DrawAnchors(context, graph, startY, endY); DrawAnchors(context, graph, startY, endY, rowHeight);
} }
} }
private void DrawCurves(DrawingContext context, Models.CommitGraph graph, double top, double bottom) private void DrawCurves(DrawingContext context, Models.CommitGraph graph, double top, double bottom, double rowHeight)
{ {
var grayedPen = new Pen(new SolidColorBrush(Colors.Gray, 0.4), Models.CommitGraph.Pens[0].Thickness); var grayedPen = new Pen(new SolidColorBrush(Colors.Gray, 0.4), Models.CommitGraph.Pens[0].Thickness);
var onlyHighlightCurrentBranch = OnlyHighlightCurrentBranch; var onlyHighlightCurrentBranch = OnlyHighlightCurrentBranch;
@ -82,16 +93,20 @@ namespace SourceGit.Views
{ {
if (link.IsMerged) if (link.IsMerged)
continue; continue;
if (link.End.Y < top)
var startY = link.Start.Y * rowHeight;
var endY = link.End.Y * rowHeight;
if (endY < top)
continue; continue;
if (link.Start.Y > bottom) if (startY > bottom)
break; break;
var geo = new StreamGeometry(); var geo = new StreamGeometry();
using (var ctx = geo.Open()) using (var ctx = geo.Open())
{ {
ctx.BeginFigure(link.Start, false); ctx.BeginFigure(new Point(link.Start.X, startY), false);
ctx.QuadraticBezierTo(link.Control, link.End); ctx.QuadraticBezierTo(new Point(link.Control.X, link.Control.Y * rowHeight), new Point(link.End.X, endY));
} }
context.DrawGeometry(null, grayedPen, geo); context.DrawGeometry(null, grayedPen, geo);
@ -100,10 +115,11 @@ namespace SourceGit.Views
foreach (var line in graph.Paths) foreach (var line in graph.Paths)
{ {
var last = line.Points[0]; var last = new Point(line.Points[0].X, line.Points[0].Y * rowHeight);
var size = line.Points.Count; var size = line.Points.Count;
var endY = line.Points[size - 1].Y * rowHeight;
if (line.Points[size - 1].Y < top) if (endY < top)
continue; continue;
if (last.Y > bottom) if (last.Y > bottom)
break; break;
@ -117,7 +133,7 @@ namespace SourceGit.Views
var ended = false; var ended = false;
for (int i = 1; i < size; i++) for (int i = 1; i < size; i++)
{ {
var cur = line.Points[i]; var cur = new Point(line.Points[i].X, line.Points[i].Y * rowHeight);
if (cur.Y < top) if (cur.Y < top)
{ {
last = cur; last = cur;
@ -173,23 +189,27 @@ namespace SourceGit.Views
{ {
if (onlyHighlightCurrentBranch && !link.IsMerged) if (onlyHighlightCurrentBranch && !link.IsMerged)
continue; continue;
if (link.End.Y < top)
var startY = link.Start.Y * rowHeight;
var endY = link.End.Y * rowHeight;
if (endY < top)
continue; continue;
if (link.Start.Y > bottom) if (startY > bottom)
break; break;
var geo = new StreamGeometry(); var geo = new StreamGeometry();
using (var ctx = geo.Open()) using (var ctx = geo.Open())
{ {
ctx.BeginFigure(link.Start, false); ctx.BeginFigure(new Point(link.Start.X, startY), false);
ctx.QuadraticBezierTo(link.Control, link.End); ctx.QuadraticBezierTo(new Point(link.Control.X, link.Control.Y * rowHeight), new Point(link.End.X, endY));
} }
context.DrawGeometry(null, Models.CommitGraph.Pens[link.Color], geo); context.DrawGeometry(null, Models.CommitGraph.Pens[link.Color], geo);
} }
} }
private void DrawAnchors(DrawingContext context, Models.CommitGraph graph, double top, double bottom) private void DrawAnchors(DrawingContext context, Models.CommitGraph graph, double top, double bottom, double rowHeight)
{ {
var dotFill = DotBrush; var dotFill = DotBrush;
var dotFillPen = new Pen(dotFill, 2); var dotFillPen = new Pen(dotFill, 2);
@ -198,9 +218,11 @@ namespace SourceGit.Views
foreach (var dot in graph.Dots) foreach (var dot in graph.Dots)
{ {
if (dot.Center.Y < top) var center = new Point(dot.Center.X, dot.Center.Y * rowHeight);
if (center.Y < top)
continue; continue;
if (dot.Center.Y > bottom) if (center.Y > bottom)
break; break;
var pen = Models.CommitGraph.Pens[dot.Color]; var pen = Models.CommitGraph.Pens[dot.Color];
@ -210,16 +232,16 @@ namespace SourceGit.Views
switch (dot.Type) switch (dot.Type)
{ {
case Models.CommitGraph.DotType.Head: case Models.CommitGraph.DotType.Head:
context.DrawEllipse(dotFill, pen, dot.Center, 6, 6); context.DrawEllipse(dotFill, pen, center, 6, 6);
context.DrawEllipse(pen.Brush, null, dot.Center, 3, 3); context.DrawEllipse(pen.Brush, null, center, 3, 3);
break; break;
case Models.CommitGraph.DotType.Merge: case Models.CommitGraph.DotType.Merge:
context.DrawEllipse(pen.Brush, null, dot.Center, 6, 6); context.DrawEllipse(pen.Brush, null, center, 6, 6);
context.DrawLine(dotFillPen, new Point(dot.Center.X, dot.Center.Y - 3), new Point(dot.Center.X, dot.Center.Y + 3)); context.DrawLine(dotFillPen, new Point(center.X, center.Y - 3), new Point(center.X, center.Y + 3));
context.DrawLine(dotFillPen, new Point(dot.Center.X - 3, dot.Center.Y), new Point(dot.Center.X + 3, dot.Center.Y)); context.DrawLine(dotFillPen, new Point(center.X - 3, center.Y), new Point(center.X + 3, center.Y));
break; break;
default: default:
context.DrawEllipse(dotFill, pen, dot.Center, 3, 3); context.DrawEllipse(dotFill, pen, center, 3, 3);
break; break;
} }
} }

View file

@ -76,7 +76,7 @@
<Style Selector="ListBoxItem"> <Style Selector="ListBoxItem">
<Setter Property="Margin" Value="0"/> <Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="0"/> <Setter Property="Padding" Value="0"/>
<Setter Property="Height" Value="28"/> <Setter Property="Height" Value="26"/>
<Setter Property="Template"> <Setter Property="Template">
<ControlTemplate> <ControlTemplate>
<Grid> <Grid>