private void DrawArrowsFromChildToParentCommits(Graphics graphics) { using (Pen arrowPen = new Pen(Color.Blue, 1)) { AdjustableArrowCap arrowCap = new AdjustableArrowCap(4, 4); arrowPen.SetLineCap(System.Drawing.Drawing2D.LineCap.RoundAnchor, System.Drawing.Drawing2D.LineCap.Custom, System.Drawing.Drawing2D.DashCap.Flat); arrowPen.CustomEndCap = arrowCap; foreach (var sprite in spritesByCommitHash.Values) { var commit = sprite.Revision; foreach (string parentHash in commit.ParentHashes) { if (Plotter.HasPlottedCommit(parentHash) && Plotter.HasPlottedCommit(commit.Hash)) { var parentSprite = spritesByCommitHash[parentHash]; float fadeInAlpha = Math.Min(parentSprite.Opacity.Value, spritesByCommitHash[commit.Hash].Opacity.Value); arrowPen.Color = Color.FromArgb((int)(fadeInAlpha * 255), Color.Blue); Point location = this.GetSpriteDrawingCoordinates(sprite); Point parentLocation = this.GetSpriteDrawingCoordinates(parentSprite); Point leftSideOfParent = new Point(parentLocation.X - circleSize / 2, parentLocation.Y); Point rightSideOfChild = new Point(location.X + circleSize / 2, location.Y); Point rightSideOfParent = new Point(parentLocation.X + circleSize / 2, parentLocation.Y); Point leftSideOfChild = new Point(location.X - circleSize / 2, location.Y); graphics.DrawLine(arrowPen, leftSideOfChild, rightSideOfParent); } } } } }
protected override void OnPaint(PaintEventArgs pe) { base.OnPaint(pe); if (DesignMode) { return; } pe.Graphics.SmoothingMode = SmoothingMode.HighQuality; DrawBackground(pe.Graphics); foreach (var sprite in spritesByCommitHash.Values) { var commit = sprite.Revision; if (!Plotter.HasPlottedCommit(commit.Hash)) { continue; } Point location = GetSpriteDrawingCoordinates(sprite); Rectangle commitBounds = new Rectangle(new Point(location.X - cellWidth / 2, location.Y - cellHeight / 2), new Size(cellWidth, cellHeight)); if (pe.ClipRectangle.IntersectsWith(commitBounds)) { Point circleUpperLeft = new Point(location.X - circleSize / 2, location.Y - circleSize / 2); Rectangle circleBounds = new Rectangle(circleUpperLeft, new Size(circleSize, circleSize)); DrawCommitCircle(pe.Graphics, sprite, circleBounds); int lineSpacing = 4; int yPosition = location.Y + circleSize / 2 + lineSpacing; string shortCommitHash = commit.Hash.Substring(0, 8); SizeF stringSize = pe.Graphics.MeasureString(shortCommitHash, this.Font); pe.Graphics.DrawString(shortCommitHash, this.Font, Brushes.Black, new Point(location.X - (int)stringSize.Width / 2, yPosition)); yPosition += (int)Math.Ceiling(stringSize.Height); const int labelMaxLength = 13; if (listOfRefsByCommitHash.ContainsKey(commit.Hash)) { foreach (GitReference reference in listOfRefsByCommitHash[commit.Hash]) { if (!ShowRemoteHeads && reference.Type == GitReferenceType.Remote) { continue; } string branchName = reference.ShortName; if (branchName.Length > labelMaxLength) { branchName = "..." + branchName.Substring(branchName.Length - labelMaxLength, labelMaxLength); } Brush refBrush; switch (reference.Type) { case GitReferenceType.Head: refBrush = Brushes.Blue; break; case GitReferenceType.Remote: refBrush = Brushes.Maroon; break; case GitReferenceType.Stash: refBrush = Brushes.Purple; break; case GitReferenceType.Tag: refBrush = Brushes.DarkGreen; break; default: refBrush = Brushes.Black; break; } stringSize = pe.Graphics.MeasureString(branchName, fontForGitRefs); var style = FontStyle.Regular; if (CurrentBranch == reference.ShortName && reference.Type == GitReferenceType.Head) { style = FontStyle.Underline; } using (Font font = new Font(fontForGitRefs, style)) { pe.Graphics.DrawString(branchName, font, refBrush, new Point(location.X - (int)stringSize.Width / 2, yPosition)); } yPosition += (int)Math.Ceiling(stringSize.Height); } } } } DrawArrowsFromChildToParentCommits(pe.Graphics); }