diff --git a/src/ViewModels/Repository.cs b/src/ViewModels/Repository.cs
index 05858d14..a7faeb35 100644
--- a/src/ViewModels/Repository.cs
+++ b/src/ViewModels/Repository.cs
@@ -281,7 +281,7 @@ namespace SourceGit.ViewModels
public void Close()
{
- SelectedView = 0.0; // Do NOT modify. Used to remove exists widgets for GC.Collect
+ SelectedView = null; // Do NOT modify. Used to remove exists widgets for GC.Collect
var settingsSerialized = JsonSerializer.Serialize(_settings, JsonCodeGen.Default.RepositorySettings);
File.WriteAllText(Path.Combine(_gitDir, "sourcegit.settings"), settingsSerialized);
diff --git a/src/Views/CommitBaseInfo.axaml b/src/Views/CommitBaseInfo.axaml
index 19b75a50..8bc19ea2 100644
--- a/src/Views/CommitBaseInfo.axaml
+++ b/src/Views/CommitBaseInfo.axaml
@@ -78,30 +78,18 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
diff --git a/src/Views/CommitRefsPresenter.cs b/src/Views/CommitRefsPresenter.cs
new file mode 100644
index 00000000..b49a8c02
--- /dev/null
+++ b/src/Views/CommitRefsPresenter.cs
@@ -0,0 +1,202 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Media;
+
+namespace SourceGit.Views
+{
+ public class CommitRefsPresenter : Control
+ {
+ public class RenderItem
+ {
+ public Geometry Icon { get; set; } = null;
+ public FormattedText Label { get; set; } = null;
+ public bool IsTag { get; set; } = false;
+ }
+
+ public static readonly StyledProperty FontFamilyProperty =
+ TextBlock.FontFamilyProperty.AddOwner();
+
+ public FontFamily FontFamily
+ {
+ get => GetValue(FontFamilyProperty);
+ set => SetValue(FontFamilyProperty, value);
+ }
+
+ public static readonly StyledProperty FontSizeProperty =
+ TextBlock.FontSizeProperty.AddOwner();
+
+ public double FontSize
+ {
+ get => GetValue(FontSizeProperty);
+ set => SetValue(FontSizeProperty, value);
+ }
+
+ public static readonly StyledProperty IconBackgroundProperty =
+ AvaloniaProperty.Register(nameof(IconBackground), Brushes.White);
+
+ public IBrush IconBackground
+ {
+ get => GetValue(IconBackgroundProperty);
+ set => SetValue(IconBackgroundProperty, value);
+ }
+
+ public static readonly StyledProperty IconForegroundProperty =
+ AvaloniaProperty.Register(nameof(IconForeground), Brushes.White);
+
+ public IBrush IconForeground
+ {
+ get => GetValue(IconForegroundProperty);
+ set => SetValue(IconForegroundProperty, value);
+ }
+
+ public static readonly StyledProperty LabelForegroundProperty =
+ AvaloniaProperty.Register(nameof(LabelForeground), Brushes.White);
+
+ public IBrush LabelForeground
+ {
+ get => GetValue(LabelForegroundProperty);
+ set => SetValue(LabelForegroundProperty, value);
+ }
+
+ public static readonly StyledProperty BranchNameBackgroundProperty =
+ AvaloniaProperty.Register(nameof(BranchNameBackground), Brushes.White);
+
+ public IBrush BranchNameBackground
+ {
+ get => GetValue(BranchNameBackgroundProperty);
+ set => SetValue(BranchNameBackgroundProperty, value);
+ }
+
+ public static readonly StyledProperty TagNameBackgroundProperty =
+ AvaloniaProperty.Register(nameof(TagNameBackground), Brushes.White);
+
+ public IBrush TagNameBackground
+ {
+ get => GetValue(TagNameBackgroundProperty);
+ set => SetValue(TagNameBackgroundProperty, value);
+ }
+
+ static CommitRefsPresenter()
+ {
+ AffectsMeasure(
+ FontFamilyProperty,
+ FontSizeProperty,
+ LabelForegroundProperty);
+
+ AffectsRender(
+ IconBackgroundProperty,
+ IconForegroundProperty,
+ BranchNameBackgroundProperty,
+ TagNameBackgroundProperty);
+ }
+
+ public override void Render(DrawingContext context)
+ {
+ if (_items.Count == 0)
+ return;
+
+ var iconFG = IconForeground;
+ var iconBG = IconBackground;
+ var branchBG = BranchNameBackground;
+ var tagBG = TagNameBackground;
+ var x = 0.0;
+
+ foreach (var item in _items)
+ {
+ var iconRect = new RoundedRect(new Rect(x, 0, 16, 16), new CornerRadius(2, 0, 0, 2));
+ var labelRect = new RoundedRect(new Rect(x + 16, 0, item.Label.Width + 8, 16), new CornerRadius(0, 2, 2, 0));
+
+ context.DrawRectangle(iconBG, null, iconRect);
+ context.DrawRectangle(item.IsTag ? tagBG : branchBG, null, labelRect);
+ context.DrawText(item.Label, new Point(x + 20, 8.0 - item.Label.Height * 0.5));
+
+ using (context.PushTransform(Matrix.CreateTranslation(x + 4, 4)))
+ context.DrawGeometry(iconFG, null, item.Icon);
+
+ x += item.Label.Width + 16 + 8 + 4;
+ }
+ }
+
+ protected override void OnDataContextChanged(EventArgs e)
+ {
+ base.OnDataContextChanged(e);
+ InvalidateMeasure();
+ }
+
+ protected override Size MeasureOverride(Size availableSize)
+ {
+ _items.Clear();
+
+ if (DataContext is Models.Commit commit && commit.HasDecorators)
+ {
+ var typeface = new Typeface(FontFamily);
+ var typefaceBold = new Typeface(FontFamily, FontStyle.Normal, FontWeight.Bold);
+ var labelFG = LabelForeground;
+ var labelSize = FontSize;
+ var requiredWidth = 0.0;
+
+ foreach (var decorator in commit.Decorators)
+ {
+ var isHead = decorator.Type == Models.DecoratorType.CurrentBranchHead ||
+ decorator.Type == Models.DecoratorType.CurrentCommitHead;
+
+ var label = new FormattedText(
+ decorator.Name,
+ CultureInfo.CurrentCulture,
+ FlowDirection.LeftToRight,
+ isHead ? typefaceBold : typeface,
+ labelSize,
+ labelFG);
+
+ var item = new RenderItem()
+ {
+ Label = label,
+ IsTag = decorator.Type == Models.DecoratorType.Tag,
+ };
+
+ var geo = null as StreamGeometry;
+ switch (decorator.Type)
+ {
+ case Models.DecoratorType.CurrentBranchHead:
+ case Models.DecoratorType.CurrentCommitHead:
+ geo = this.FindResource("Icons.Check") as StreamGeometry;
+ break;
+ case Models.DecoratorType.RemoteBranchHead:
+ geo = this.FindResource("Icons.Remote") as StreamGeometry;
+ break;
+ case Models.DecoratorType.Tag:
+ geo = this.FindResource("Icons.Tag") as StreamGeometry;
+ break;
+ default:
+ geo = this.FindResource("Icons.Branch") as StreamGeometry;
+ break;
+ }
+
+ var drawGeo = geo.Clone();
+ var iconBounds = drawGeo.Bounds;
+ var translation = Matrix.CreateTranslation(-(Vector)iconBounds.Position);
+ var scale = Math.Min(8.0 / iconBounds.Width, 8.0 / iconBounds.Height);
+ var transform = translation * Matrix.CreateScale(scale, scale);
+ if (drawGeo.Transform == null || drawGeo.Transform.Value == Matrix.Identity)
+ drawGeo.Transform = new MatrixTransform(transform);
+ else
+ drawGeo.Transform = new MatrixTransform(drawGeo.Transform.Value * transform);
+
+ item.Icon = drawGeo;
+ _items.Add(item);
+ requiredWidth += label.Width + 16 /* icon */ + 8 /* label margin */ + 4 /* item right margin */;
+ }
+
+ return new Size(requiredWidth, 16);
+ }
+
+ return new Size(0, 0);
+ }
+
+ private List _items = new List();
+ }
+}
diff --git a/src/Views/Histories.axaml b/src/Views/Histories.axaml
index 74818238..bf6b75f4 100644
--- a/src/Views/Histories.axaml
+++ b/src/Views/Histories.axaml
@@ -69,38 +69,16 @@
Margin="0,0,4,0"
Fill="{DynamicResource Brush.FG1}"
IsVisible="{Binding CanPullFromUpstream}"/>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
((h, _) =>
{
+ if (h.DataContext == null)
+ return;
+
// Force scroll selected item (current head) into view. see issue #58
var datagrid = h.CommitDataGrid;
if (datagrid != null && datagrid.SelectedItems.Count == 1)