mirror of
https://github.com/sourcegit-scm/sourcegit.git
synced 2024-12-26 21:17:20 -08:00
Compare commits
8 commits
e945367b28
...
268dd9849d
Author | SHA1 | Date | |
---|---|---|---|
|
268dd9849d | ||
|
fbfca7b4a5 | ||
|
4b5d65cdb7 | ||
|
fe015f9bfd | ||
|
c7332aff03 | ||
|
18e0479288 | ||
|
3af30f54b6 | ||
|
d5671ea8df |
4 changed files with 164 additions and 102 deletions
|
@ -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();
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue