mirror of
https://github.com/sourcegit-scm/sourcegit.git
synced 2024-11-01 13:13:21 -07:00
96d4150d26
* remove dotnet-tool.json because the project does not rely on any dotnet tools. * remove Directory.Build.props because the solution has only one project. * move src/SourceGit to src. It's not needed to put all sources into a subfolder of src since there's only one project.
249 lines
8.3 KiB
C#
249 lines
8.3 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
|
|
using Avalonia;
|
|
|
|
namespace SourceGit.Models
|
|
{
|
|
public class CommitGraph
|
|
{
|
|
public class Path
|
|
{
|
|
public List<Point> Points = new List<Point>();
|
|
public int Color = 0;
|
|
}
|
|
|
|
public class PathHelper
|
|
{
|
|
public string Next;
|
|
public bool IsMerged;
|
|
public double LastX;
|
|
public double LastY;
|
|
public double EndY;
|
|
public Path Path;
|
|
|
|
public PathHelper(string next, bool isMerged, int color, Point start)
|
|
{
|
|
Next = next;
|
|
IsMerged = isMerged;
|
|
LastX = start.X;
|
|
LastY = start.Y;
|
|
EndY = LastY;
|
|
|
|
Path = new Path();
|
|
Path.Color = color;
|
|
Path.Points.Add(start);
|
|
}
|
|
|
|
public PathHelper(string next, bool isMerged, int color, Point start, Point to)
|
|
{
|
|
Next = next;
|
|
IsMerged = isMerged;
|
|
LastX = to.X;
|
|
LastY = to.Y;
|
|
EndY = LastY;
|
|
|
|
Path = new Path();
|
|
Path.Color = color;
|
|
Path.Points.Add(start);
|
|
Path.Points.Add(to);
|
|
}
|
|
|
|
public void Add(double x, double y, double halfHeight, bool isEnd = false)
|
|
{
|
|
if (x > LastX)
|
|
{
|
|
Add(new Point(LastX, LastY));
|
|
Add(new Point(x, y - halfHeight));
|
|
if (isEnd)
|
|
Add(new Point(x, y));
|
|
}
|
|
else if (x < LastX)
|
|
{
|
|
if (y > LastY + halfHeight)
|
|
Add(new Point(LastX, LastY + halfHeight));
|
|
Add(new Point(x, y));
|
|
}
|
|
else if (isEnd)
|
|
{
|
|
Add(new Point(x, y));
|
|
}
|
|
|
|
LastX = x;
|
|
LastY = y;
|
|
}
|
|
|
|
private void Add(Point p)
|
|
{
|
|
if (EndY < p.Y)
|
|
{
|
|
Path.Points.Add(p);
|
|
EndY = p.Y;
|
|
}
|
|
}
|
|
}
|
|
|
|
public class Link
|
|
{
|
|
public Point Start;
|
|
public Point Control;
|
|
public Point End;
|
|
public int Color;
|
|
}
|
|
|
|
public class Dot
|
|
{
|
|
public Point Center;
|
|
public int Color;
|
|
}
|
|
|
|
public List<Path> Paths { get; set; } = new List<Path>();
|
|
public List<Link> Links { get; set; } = new List<Link>();
|
|
public List<Dot> Dots { get; set; } = new List<Dot>();
|
|
|
|
public static CommitGraph Parse(List<Commit> commits, double rowHeight, int colorCount)
|
|
{
|
|
double UNIT_WIDTH = 12;
|
|
double HALF_WIDTH = 6;
|
|
double UNIT_HEIGHT = rowHeight;
|
|
double HALF_HEIGHT = rowHeight / 2;
|
|
|
|
var temp = new CommitGraph();
|
|
var unsolved = new List<PathHelper>();
|
|
var mapUnsolved = new Dictionary<string, PathHelper>();
|
|
var ended = new List<PathHelper>();
|
|
var offsetY = -HALF_HEIGHT;
|
|
var colorIdx = 0;
|
|
|
|
foreach (var commit in commits)
|
|
{
|
|
var major = null as PathHelper;
|
|
var isMerged = commit.IsMerged;
|
|
var oldCount = unsolved.Count;
|
|
|
|
// Update current y offset
|
|
offsetY += UNIT_HEIGHT;
|
|
|
|
// Find first curves that links to this commit and marks others that links to this commit ended.
|
|
double offsetX = -HALF_WIDTH;
|
|
foreach (var l in unsolved)
|
|
{
|
|
if (l.Next == commit.SHA)
|
|
{
|
|
if (major == null)
|
|
{
|
|
offsetX += UNIT_WIDTH;
|
|
major = l;
|
|
|
|
if (commit.Parents.Count > 0)
|
|
{
|
|
major.Next = commit.Parents[0];
|
|
if (!mapUnsolved.ContainsKey(major.Next))
|
|
mapUnsolved.Add(major.Next, major);
|
|
}
|
|
else
|
|
{
|
|
major.Next = "ENDED";
|
|
ended.Add(l);
|
|
}
|
|
|
|
major.Add(offsetX, offsetY, HALF_HEIGHT);
|
|
}
|
|
else
|
|
{
|
|
ended.Add(l);
|
|
}
|
|
|
|
isMerged = isMerged || l.IsMerged;
|
|
}
|
|
else
|
|
{
|
|
if (!mapUnsolved.ContainsKey(l.Next))
|
|
mapUnsolved.Add(l.Next, l);
|
|
offsetX += UNIT_WIDTH;
|
|
l.Add(offsetX, offsetY, HALF_HEIGHT);
|
|
}
|
|
}
|
|
|
|
// Create new curve for branch head
|
|
if (major == null && commit.Parents.Count > 0)
|
|
{
|
|
offsetX += UNIT_WIDTH;
|
|
major = new PathHelper(commit.Parents[0], isMerged, colorIdx, new Point(offsetX, offsetY));
|
|
unsolved.Add(major);
|
|
temp.Paths.Add(major.Path);
|
|
colorIdx = (colorIdx + 1) % colorCount;
|
|
}
|
|
|
|
// Calculate link position of this commit.
|
|
Point position = new Point(offsetX, offsetY);
|
|
if (major != null)
|
|
{
|
|
major.IsMerged = isMerged;
|
|
position = new Point(major.LastX, offsetY);
|
|
temp.Dots.Add(new Dot() { Center = position, Color = major.Path.Color });
|
|
}
|
|
else
|
|
{
|
|
temp.Dots.Add(new Dot() { Center = position, Color = 0 });
|
|
}
|
|
|
|
// Deal with parents
|
|
for (int j = 1; j < commit.Parents.Count; j++)
|
|
{
|
|
var parent = commit.Parents[j];
|
|
if (mapUnsolved.TryGetValue(parent, out var value))
|
|
{
|
|
var l = value;
|
|
var link = new Link();
|
|
|
|
link.Start = position;
|
|
link.End = new Point(l.LastX, offsetY + HALF_HEIGHT);
|
|
link.Control = new Point(link.End.X, link.Start.Y);
|
|
link.Color = l.Path.Color;
|
|
temp.Links.Add(link);
|
|
}
|
|
else
|
|
{
|
|
offsetX += UNIT_WIDTH;
|
|
|
|
// Create new curve for parent commit that not includes before
|
|
var l = new PathHelper(commit.Parents[j], isMerged, colorIdx, position, new Point(offsetX, position.Y + HALF_HEIGHT));
|
|
unsolved.Add(l);
|
|
temp.Paths.Add(l.Path);
|
|
colorIdx = (colorIdx + 1) % colorCount;
|
|
}
|
|
}
|
|
|
|
// Remove ended curves from unsolved
|
|
foreach (var l in ended)
|
|
{
|
|
l.Add(position.X, position.Y, HALF_HEIGHT, true);
|
|
unsolved.Remove(l);
|
|
}
|
|
|
|
// Margins & merge state (used by datagrid).
|
|
commit.IsMerged = isMerged;
|
|
commit.Margin = new Thickness(Math.Max(offsetX + HALF_WIDTH, oldCount * UNIT_WIDTH), 0, 0, 0);
|
|
|
|
// Clean up
|
|
ended.Clear();
|
|
mapUnsolved.Clear();
|
|
}
|
|
|
|
// Deal with curves haven't ended yet.
|
|
for (int i = 0; i < unsolved.Count; i++)
|
|
{
|
|
var path = unsolved[i];
|
|
var endY = (commits.Count - 0.5) * UNIT_HEIGHT;
|
|
|
|
if (path.Path.Points.Count == 1 && path.Path.Points[0].Y == endY)
|
|
continue;
|
|
path.Add((i + 0.5) * UNIT_WIDTH, endY + HALF_HEIGHT, HALF_HEIGHT, true);
|
|
}
|
|
unsolved.Clear();
|
|
|
|
return temp;
|
|
}
|
|
}
|
|
}
|