Compare commits

..

8 commits

Author SHA1 Message Date
leo
268dd9849d
enhance: better margin of commit subject (#528)
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
2024-09-29 19:56:16 +08:00
leo
fbfca7b4a5
enhance: better graph for ended orphan branch (#528) 2024-09-29 18:41:50 +08:00
leo
4b5d65cdb7
refactor: rewrite Models.CommitGraph.PathHelper (#528) 2024-09-29 18:16:28 +08:00
leo
fe015f9bfd
fix: endpoint of a graph path has been added twice (#528) 2024-09-29 16:45:50 +08:00
GadflyFang
c7332aff03
fix: avoid NRE in ContextMenuExtension (#526) 2024-09-29 16:05:02 +08:00
GadflyFang
18e0479288
enhance: reduce Minimum of History Commits setting (#527) 2024-09-29 15:23:38 +08:00
leo
3af30f54b6
enhance: avoid flicker at the first time clicking on text diff view 2024-09-29 14:16:42 +08:00
leo
d5671ea8df
enhance: only re-calculate highlight chunk when it is needed 2024-09-29 13:48:48 +08:00
4 changed files with 164 additions and 102 deletions

View file

@ -20,7 +20,6 @@ namespace SourceGit.Models
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)
@ -29,7 +28,6 @@ namespace SourceGit.Models
IsMerged = isMerged;
LastX = start.X;
LastY = start.Y;
EndY = LastY;
Path = new Path();
Path.Color = color;
@ -42,7 +40,6 @@ namespace SourceGit.Models
IsMerged = isMerged;
LastX = to.X;
LastY = to.Y;
EndY = LastY;
Path = new Path();
Path.Color = color;
@ -50,43 +47,91 @@ namespace SourceGit.Models
Path.Points.Add(to);
}
public void Add(double x, double y, double halfHeight, bool isEnd = false)
/// <summary>
/// A path that just passed this row.
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="halfHeight"></param>
public void Pass(double x, double y, double halfHeight)
{
if (x > LastX)
{
Add(new Point(LastX, LastY));
Add(new Point(x, y - halfHeight));
if (isEnd)
Add(new Point(x, y));
Add(LastX, LastY);
Add(x, y - halfHeight);
}
else if (x < LastX)
{
var testY = LastY + halfHeight;
if (y > testY)
Add(new Point(LastX, testY));
if (!isEnd)
Add(LastX, y - halfHeight);
y += halfHeight;
Add(new Point(x, y));
}
else if (isEnd)
{
Add(new Point(x, y));
Add(x, y);
}
LastX = x;
LastY = y;
}
private void Add(Point p)
/// <summary>
/// A path that has commit in this row but not ended
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="halfHeight"></param>
public void Goto(double x, double y, double halfHeight)
{
if (EndY < p.Y)
if (x > LastX)
{
Path.Points.Add(p);
EndY = p.Y;
Add(LastX, LastY);
Add(x, y - halfHeight);
}
else if (x < LastX)
{
var minY = y - halfHeight;
if (minY > LastY)
minY -= halfHeight;
Add(LastX, minY);
Add(x, y);
}
LastX = x;
LastY = y;
}
/// <summary>
/// A path that has commit in this row and end.
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="halfHeight"></param>
public void End(double x, double y, double halfHeight)
{
if (x > LastX)
{
Add(LastX, LastY);
Add(x, y - halfHeight);
}
else if (x < LastX)
{
Add(LastX, y - halfHeight);
}
Add(x, y);
LastX = x;
LastY = y;
}
private void Add(double x, double y)
{
if (_endY < y)
{
Path.Points.Add(new Point(x, y));
_endY = y;
}
}
private double _endY = 0;
}
public class Link
@ -146,7 +191,6 @@ namespace SourceGit.Models
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;
@ -155,13 +199,13 @@ namespace SourceGit.Models
{
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 = H_MARGIN - HALF_WIDTH;
var offsetX = 4 - HALF_WIDTH;
var maxOffsetOld = unsolved.Count > 0 ? unsolved[^1].LastX : offsetX + UNIT_WIDTH;
foreach (var l in unsolved)
{
if (l.Next == commit.SHA)
@ -174,19 +218,17 @@ namespace SourceGit.Models
if (commit.Parents.Count > 0)
{
major.Next = commit.Parents[0];
if (!mapUnsolved.ContainsKey(major.Next))
mapUnsolved.Add(major.Next, major);
major.Goto(offsetX, offsetY, HALF_HEIGHT);
}
else
{
major.Next = "ENDED";
major.End(offsetX, offsetY, HALF_HEIGHT);
ended.Add(l);
}
major.Add(offsetX, offsetY, HALF_HEIGHT);
}
else
{
l.End(major.LastX, offsetY, HALF_HEIGHT);
ended.Add(l);
}
@ -195,13 +237,16 @@ namespace SourceGit.Models
}
else
{
if (!mapUnsolved.ContainsKey(l.Next))
mapUnsolved.Add(l.Next, l);
offsetX += UNIT_WIDTH;
l.Add(offsetX, offsetY, HALF_HEIGHT);
l.Pass(offsetX, offsetY, HALF_HEIGHT);
}
}
// Remove ended curves from unsolved
foreach (var l in ended)
unsolved.Remove(l);
ended.Clear();
// Create new curve for branch head
if (major == null)
{
@ -218,13 +263,8 @@ namespace SourceGit.Models
}
// Calculate link position of this commit.
Point position = new Point(offsetX, offsetY);
int dotColor = 0;
if (major != null)
{
position = new Point(major.LastX, offsetY);
dotColor = major.Path.Color;
}
Point position = new Point(major?.LastX ?? offsetX, offsetY);
int dotColor = major?.Path.Color ?? 0;
Dot anchor = new Dot() { Center = position, Color = dotColor };
if (commit.IsCurrentHead)
anchor.Type = DotType.Head;
@ -239,11 +279,12 @@ namespace SourceGit.Models
{
for (int j = 1; j < commit.Parents.Count; j++)
{
var parent = commit.Parents[j];
if (mapUnsolved.TryGetValue(parent, out var value))
var parentSHA = commit.Parents[j];
var parent = unsolved.Find(x => x.Next.Equals(parentSHA, StringComparison.Ordinal));
if (parent != null)
{
// Try to change the merge state of linked graph
var l = value;
var l = parent;
if (isMerged)
l.IsMerged = true;
@ -260,7 +301,7 @@ namespace SourceGit.Models
offsetX += UNIT_WIDTH;
// Create new curve for parent commit that not includes before
var l = new PathHelper(parent, isMerged, colorIdx, position, new Point(offsetX, position.Y + HALF_HEIGHT));
var l = new PathHelper(parentSHA, isMerged, colorIdx, position, new Point(offsetX, position.Y + HALF_HEIGHT));
unsolved.Add(l);
temp.Paths.Add(l.Path);
colorIdx = (colorIdx + 1) % _penCount;
@ -268,20 +309,9 @@ namespace SourceGit.Models
}
}
// 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 Views.Histories).
commit.IsMerged = isMerged;
commit.Margin = new Thickness(Math.Max(offsetX + HALF_WIDTH, oldCount * UNIT_WIDTH + H_MARGIN) + H_MARGIN, 0, 0, 0);
// Clean up
ended.Clear();
mapUnsolved.Clear();
commit.Margin = new Thickness(Math.Max(offsetX, maxOffsetOld) + HALF_WIDTH + H_MARGIN, 0, 0, 0);
}
// Deal with curves haven't ended yet.
@ -293,7 +323,7 @@ namespace SourceGit.Models
if (path.Path.Points.Count == 1 && Math.Abs(path.Path.Points[0].Y - endY) < 0.0001)
continue;
path.Add((i + 0.5) * UNIT_WIDTH + H_MARGIN, endY + HALF_HEIGHT, HALF_HEIGHT, true);
path.End((i + 0.5) * UNIT_WIDTH + 4, endY + HALF_HEIGHT, HALF_HEIGHT);
}
unsolved.Clear();

View file

@ -1,5 +1,4 @@
using System.ComponentModel;
using Avalonia.Controls;
namespace SourceGit.Views
@ -15,7 +14,7 @@ namespace SourceGit.Views
menu.Closing += OnContextMenuClosing; // Clear context menu because it is dynamic.
control.ContextMenu = menu;
control.ContextMenu.Open();
control.ContextMenu?.Open();
}
private static void OnContextMenuClosing(object sender, CancelEventArgs e)

View file

@ -99,7 +99,7 @@
Margin="0,0,16,0"/>
<Grid Grid.Row="3" Grid.Column="1" ColumnDefinitions="*,64">
<Slider Grid.Column="0"
Minimum="20000" Maximum="100000"
Minimum="5000" Maximum="100000"
TickPlacement="BottomRight" TickFrequency="5000"
IsSnapToTickEnabled="True"
VerticalAlignment="Center"

View file

@ -437,8 +437,8 @@ namespace SourceGit.Views
base.OnLoaded(e);
TextArea.TextView.ContextRequested += OnTextViewContextRequested;
TextArea.TextView.PointerEntered += OnTextViewPointerEntered;
TextArea.TextView.PointerMoved += OnTextViewPointerMoved;
TextArea.TextView.PointerEntered += OnTextViewPointerChanged;
TextArea.TextView.PointerMoved += OnTextViewPointerChanged;
TextArea.TextView.PointerWheelChanged += OnTextViewPointerWheelChanged;
UpdateTextMate();
@ -449,8 +449,8 @@ namespace SourceGit.Views
base.OnUnloaded(e);
TextArea.TextView.ContextRequested -= OnTextViewContextRequested;
TextArea.TextView.PointerEntered -= OnTextViewPointerEntered;
TextArea.TextView.PointerMoved -= OnTextViewPointerMoved;
TextArea.TextView.PointerEntered -= OnTextViewPointerChanged;
TextArea.TextView.PointerMoved -= OnTextViewPointerChanged;
TextArea.TextView.PointerWheelChanged -= OnTextViewPointerWheelChanged;
if (_textMate != null)
@ -510,10 +510,19 @@ namespace SourceGit.Views
e.Handled = true;
}
private void OnTextViewPointerEntered(object sender, PointerEventArgs e)
private void OnTextViewPointerChanged(object sender, PointerEventArgs e)
{
if (EnableChunkSelection && sender is TextView view)
{
var selection = TextArea.Selection;
if (selection == null || selection.IsEmpty)
{
if (_lastSelectStart != _lastSelectEnd)
{
_lastSelectStart = TextLocation.Empty;
_lastSelectEnd = TextLocation.Empty;
}
var chunk = SelectedChunk;
if (chunk != null)
{
@ -523,21 +532,20 @@ namespace SourceGit.Views
}
UpdateSelectedChunk(e.GetPosition(view).Y + view.VerticalOffset);
}
}
private void OnTextViewPointerMoved(object sender, PointerEventArgs e)
{
if (EnableChunkSelection && sender is TextView view)
{
var chunk = SelectedChunk;
if (chunk != null)
{
var rect = new Rect(0, chunk.Y, Bounds.Width, chunk.Height);
if (rect.Contains(e.GetPosition(this)))
return;
}
var start = selection.StartPosition.Location;
var end = selection.EndPosition.Location;
if (_lastSelectStart != start || _lastSelectEnd != end)
{
_lastSelectStart = start;
_lastSelectEnd = end;
UpdateSelectedChunk(e.GetPosition(view).Y + view.VerticalOffset);
return;
}
if (SelectedChunk == null)
UpdateSelectedChunk(e.GetPosition(view).Y + view.VerticalOffset);
}
}
@ -657,7 +665,9 @@ namespace SourceGit.Views
}
private TextMate.Installation _textMate = null;
protected LineStyleTransformer _lineStyleTransformer = null;
private TextLocation _lastSelectStart = TextLocation.Empty;
private TextLocation _lastSelectEnd = TextLocation.Empty;
private LineStyleTransformer _lineStyleTransformer = null;
}
public class CombinedTextDiffPresenter : ThemedTextDiffPresenter
@ -684,18 +694,6 @@ namespace SourceGit.Views
return 0;
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
var scroller = (ScrollViewer)e.NameScope.Find("PART_ScrollViewer");
if (scroller != null)
{
scroller.Bind(ScrollViewer.OffsetProperty, new Binding("SyncScrollOffset", BindingMode.TwoWay));
scroller.GotFocus += (_, _) => TrySetChunk(null);
}
}
public override void UpdateSelectedChunk(double y)
{
var diff = DataContext as Models.TextDiff;
@ -812,6 +810,27 @@ namespace SourceGit.Views
}
}
protected override void OnLoaded(RoutedEventArgs e)
{
base.OnLoaded(e);
var scroller = this.FindDescendantOfType<ScrollViewer>();
if (scroller != null)
{
scroller.Bind(ScrollViewer.OffsetProperty, new Binding("SyncScrollOffset", BindingMode.TwoWay));
scroller.GotFocus += OnTextViewScrollGotFocus;
}
}
protected override void OnUnloaded(RoutedEventArgs e)
{
var scroller = this.FindDescendantOfType<ScrollViewer>();
if (scroller != null)
scroller.GotFocus -= OnTextViewScrollGotFocus;
base.OnUnloaded(e);
}
protected override void OnDataContextChanged(EventArgs e)
{
base.OnDataContextChanged(e);
@ -843,6 +862,16 @@ namespace SourceGit.Views
GC.Collect();
}
private void OnTextViewScrollGotFocus(object sender, GotFocusEventArgs e)
{
if (EnableChunkSelection && sender is ScrollViewer viewer)
{
var area = viewer.FindDescendantOfType<TextArea>();
if (!area.IsPointerOver)
TrySetChunk(null);
}
}
}
public class SingleSideTextDiffPresenter : ThemedTextDiffPresenter
@ -1011,8 +1040,6 @@ namespace SourceGit.Views
protected override void OnUnloaded(RoutedEventArgs e)
{
base.OnUnloaded(e);
if (_scrollViewer != null)
{
_scrollViewer.ScrollChanged -= OnTextViewScrollChanged;
@ -1022,6 +1049,7 @@ namespace SourceGit.Views
TextArea.PointerWheelChanged -= OnTextAreaPointerWheelChanged;
base.OnUnloaded(e);
GC.Collect();
}
@ -1057,8 +1085,13 @@ namespace SourceGit.Views
private void OnTextViewScrollGotFocus(object sender, GotFocusEventArgs e)
{
if (EnableChunkSelection && sender is ScrollViewer viewer)
{
var area = viewer.FindDescendantOfType<TextArea>();
if (!area.IsPointerOver)
TrySetChunk(null);
}
}
private void OnTextViewScrollChanged(object sender, ScrollChangedEventArgs e)
{