Skip to content

Commit

Permalink
Blame: Display author avatar and a recency marker in the gutter
Browse files Browse the repository at this point in the history
+ add a setting to disable it

Note: Height estimation (proposed in gitextensions#6605 (comment) )
  • Loading branch information
pmiossec committed Apr 2, 2020
1 parent e489032 commit 9eebfe6
Show file tree
Hide file tree
Showing 10 changed files with 276 additions and 10 deletions.
6 changes: 6 additions & 0 deletions GitCommands/Settings/AppSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1688,6 +1688,12 @@ public static bool BlameShowOriginalFilePath
set => SetBool("Blame.ShowOriginalFilePath", value);
}

public static bool BlameShowAuthorAvatar
{
get => GetBool("Blame.ShowAuthorAvatar", true);
set => SetBool("Blame.ShowAuthorAvatar", value);
}

public static bool IsPortable()
{
return Properties.Settings.Default.IsPortable;
Expand Down
2 changes: 1 addition & 1 deletion GitUI/Avatars/AvatarService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace GitUI.Avatars
{
public static class AvatarService
{
private static InitialsAvatarGenerator AvatarGenerator = new InitialsAvatarGenerator();
private static readonly InitialsAvatarGenerator AvatarGenerator = new InitialsAvatarGenerator();
public static IAvatarProvider Default { get; }
= new BackupAvatarProvider(new AvatarMemoryCache(new AvatarPersistentCache(new AvatarDownloader(AvatarGenerator), AvatarGenerator)),
Images.User80);
Expand Down
12 changes: 11 additions & 1 deletion GitUI/CommandsDialogs/FormFileHistory.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions GitUI/CommandsDialogs/FormFileHistory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ public FormFileHistory(GitUICommands commands, string fileName, GitRevision revi
detectMoveAndCopyInAllFilesToolStripMenuItem.Checked = AppSettings.DetectCopyInAllOnBlame;
detectMoveAndCopyInThisFileToolStripMenuItem.Checked = AppSettings.DetectCopyInFileOnBlame;
displayAuthorFirstToolStripMenuItem.Checked = AppSettings.BlameDisplayAuthorFirst;
showAuthorAvatarToolStripMenuItem.Checked = AppSettings.BlameShowAuthorAvatar;
showAuthorToolStripMenuItem.Checked = AppSettings.BlameShowAuthor;
showAuthorDateToolStripMenuItem.Checked = AppSettings.BlameShowAuthorDate;
showAuthorTimeToolStripMenuItem.Checked = AppSettings.BlameShowAuthorTime;
Expand Down Expand Up @@ -704,5 +705,12 @@ private void showOriginalFilePathToolStripMenuItem_Click(object sender, EventArg
showOriginalFilePathToolStripMenuItem.Checked = AppSettings.BlameShowOriginalFilePath;
UpdateSelectedFileViewers(true);
}

private void showAuthorAvatarToolStripMenuItem_Click(object sender, EventArgs e)
{
AppSettings.BlameShowAuthorAvatar = !AppSettings.BlameShowAuthorAvatar;
showAuthorAvatarToolStripMenuItem.Checked = AppSettings.BlameShowAuthorAvatar;
UpdateSelectedFileViewers(true);
}
}
}
118 changes: 118 additions & 0 deletions GitUI/Editor/BlameAuthorMargin.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using GitExtUtils.GitUI;
using ICSharpCode.TextEditor;
using Microsoft.VisualStudio.Threading;

namespace GitUI.Editor
{
public class GitBlameDisplay
{
public JoinableTask<Image> Avatar { get; set; }
public int RecencyIndex { get; set; }
public Color RecencyColor { get; set; }
}

/// <summary>
/// This class display avatars in the gutter in a blame.
/// </summary>
public class BlameAuthorMargin : AbstractMargin
{
private static readonly int RecencyIndexWidth = Convert.ToInt32(3 * DpiUtil.ScaleX);
private List<Image> _avatars;
private readonly int _lineHeight;
private readonly Color _backgroundColor;
private List<GitBlameDisplay> _blameLines;
private Dictionary<int, SolidBrush> _brushs = new Dictionary<int, SolidBrush>();
private bool _isVisible = true;

public BlameAuthorMargin(TextArea textArea) : base(textArea)
{
_lineHeight = GetFontHeight(textArea.Font);
_backgroundColor = ((SolidBrush)SystemBrushes.Window).Color;
}

private static int GetFontHeight(Font font)
{
var max = Math.Max(
TextRenderer.MeasureText("_", font).Height,
(int)Math.Ceiling(font.GetHeight()));

return max + 1;
}

public void Initialize(List<GitBlameDisplay> blameLines)
{
_blameLines = blameLines;
_avatars = blameLines.Select(a => ThreadHelper.JoinableTaskFactory.Run(async () => await a.Avatar)).ToList();

// Update the resolution otherwise the image is not drawn at the good size :(
foreach (var avatar in _avatars)
{
if (avatar is Bitmap bitmapAvatar)
{
bitmapAvatar.SetResolution(DpiUtil.DpiX, DpiUtil.DpiY);
}
}

// Build brushes
foreach (var blameLine in blameLines)
{
if (!_brushs.ContainsKey(blameLine.RecencyIndex))
{
_brushs.Add(blameLine.RecencyIndex, new SolidBrush(blameLine.RecencyColor));
}
}
}

public override int Width => _lineHeight + RecencyIndexWidth;

public void SetVisiblity(bool isVisible)
{
_isVisible = isVisible;
}

public override bool IsVisible => _isVisible;

public override void Paint(Graphics g, Rectangle rect)
{
if (rect.Width <= 0 || rect.Height <= 0)
{
return;
}

g.Clear(_backgroundColor);

if (_avatars == null || _avatars.Count == 0)
{
return;
}

var verticalOffset = textArea.VirtualTop.Y;
var lineStart = verticalOffset / _lineHeight;
var negativeOffset = (lineStart * _lineHeight) - verticalOffset;
var lineCount = (int)rect.Height / _lineHeight;

for (int i = 0; i < lineCount; i++)
{
if (lineStart + i >= _avatars.Count)
{
break;
}

int y = negativeOffset + (i * _lineHeight);
g.FillRectangle(_brushs[_blameLines[lineStart + i].RecencyIndex], _lineHeight, y, RecencyIndexWidth, _lineHeight);

if (_avatars[lineStart + i] != null)
{
g.DrawImage(_avatars[lineStart + i], new Point(0, y));
}
}

base.Paint(g, rect);
}
}
}
6 changes: 6 additions & 0 deletions GitUI/Editor/FileViewer.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.IO;
Expand Down Expand Up @@ -1618,5 +1619,10 @@ public bool ShowSyntaxHighlightingInDiff
public ToolStripButton IgnoreAllWhitespacesButton => _fileViewer.ignoreAllWhitespaces;
public ToolStripMenuItem IgnoreAllWhitespacesMenuItem => _fileViewer.ignoreAllWhitespaceChangesToolStripMenuItem;
}

public void SetGutterAvatars(List<GitBlameDisplay> gitBlameDisplays)
{
internalFileViewer.SetGutterAvatars(gitBlameDisplays);
}
}
}
26 changes: 26 additions & 0 deletions GitUI/Editor/FileViewerInternal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public partial class FileViewerInternal : GitModuleControl, IFileViewer
private readonly CurrentViewPositionCache _currentViewPositionCache;
private DiffViewerLineNumberControl _lineNumbersControl;
private DiffHighlightService _diffHighlightService = DiffHighlightService.Instance;
private BlameAuthorMargin _authorsAvatarMargin;

public FileViewerInternal()
{
Expand Down Expand Up @@ -646,5 +647,30 @@ public TestAccessor(FileViewerInternal control)

public TextEditorControl TextEditor => _control.TextEditor;
}

public void SetGutterAvatars(List<GitBlameDisplay> avatars)
{
if (!AppSettings.BlameShowAuthorAvatar)
{
if (_authorsAvatarMargin != null)
{
_authorsAvatarMargin.SetVisiblity(false);
}

return;
}

if (_authorsAvatarMargin == null)
{
_authorsAvatarMargin = new BlameAuthorMargin(TextEditor.ActiveTextAreaControl.TextArea);
TextEditor.ActiveTextAreaControl.TextArea.InsertLeftMargin(0, _authorsAvatarMargin);
}
else
{
_authorsAvatarMargin.SetVisiblity(true);
}

_authorsAvatarMargin.Initialize(avatars);
}
}
}
4 changes: 4 additions & 0 deletions GitUI/Translation/English.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -4240,6 +4240,10 @@ If you are not sure just close this window.</source>
<source>Difftool selected &lt; - &gt; local</source>
<target />
</trans-unit>
<trans-unit id="disableRecentHighlightingToolStripMenuItem.Text">
<source>Disable recent highlighting</source>
<target />
</trans-unit>
<trans-unit id="displayAuthorFirstToolStripMenuItem.Text">
<source>Display author first</source>
<target />
Expand Down
Loading

0 comments on commit 9eebfe6

Please sign in to comment.