public GitRevision GetRowData(int aRow) { lock (_graphData) { Graph.ILaneRow row = _graphData[aRow]; return(row == null ? null : row.Node.Data); } }
private bool DrawVisibleGraph(int start, int end) { for (int rowIndex = start; rowIndex < end; rowIndex++) { Graph.ILaneRow row = _graphData[rowIndex]; if (row == null) { // This shouldn't be happening...If it does, clear the cache so we // eventually pick it up. Debug.WriteLine("Draw lane {0} NO DATA", rowIndex.ToString()); ClearDrawCache(); return(false); } Region oldClip = _graphWorkArea.Clip; // Get the x,y value of the current item's upper left in the cache int curCacheRow = (_cacheHeadRow + rowIndex - _cacheHead) % _cacheCountMax; const int x = 0; int y = curCacheRow * _rowHeight; var laneRect = new Rectangle(0, y, Width, _rowHeight); if (rowIndex == start || curCacheRow == 0) { // Draw previous row first. Clip top to row. We also need to clear the area // before we draw since nothing else would clear the top 1/2 of the item to draw. _graphWorkArea.RenderingOrigin = new Point(x, y - _rowHeight); var newClip = new Region(laneRect); _graphWorkArea.Clip = newClip; _graphWorkArea.Clear(Color.Transparent); DrawItem(_graphWorkArea, _graphData[rowIndex - 1]); _graphWorkArea.Clip = oldClip; } bool isLast = rowIndex == end - 1; if (isLast) { var newClip = new Region(laneRect); _graphWorkArea.Clip = newClip; } _graphWorkArea.RenderingOrigin = new Point(x, y); bool success = DrawItem(_graphWorkArea, row); _graphWorkArea.Clip = oldClip; if (!success) { ClearDrawCache(); return(false); } } return(true); }
public string GetRowId(int aRow) { lock (_graphData) { Graph.ILaneRow row = _graphData[aRow]; if (row == null) { return(null); } return(row.Node.Id); } }
public IComparable GetRowId(int aRow) { lock (graphData) { Graph.ILaneRow row = graphData[aRow]; if (row == null) { return(null); } return(row.Node.Id); } }
public object GetRowData(int aRow) { lock (graphData) { Graph.ILaneRow row = graphData[aRow]; if (row == null) { return(null); } return(row.Node.Data); } }
public bool RowIsRelative(int aRow) { lock (_graphData) { Graph.ILaneRow row = _graphData[aRow]; if (row == null) { return(false); } if (row.Node.Ancestors.Count > 0) { return(row.Node.Ancestors[0].IsRelative); } return(true); } }
private void dataGrid_CellPainting(object sender, DataGridViewCellPaintingEventArgs e) { if (e.RowIndex < 0) { return; } if (Rows[e.RowIndex].Height != RowTemplate.Height) { Rows[e.RowIndex].Height = RowTemplate.Height; dataGrid_Scroll(null, null); } lock (_graphData) { Graph.ILaneRow row = _graphData[e.RowIndex]; if (row == null || (e.State & DataGridViewElementStates.Visible) == 0) { return; } if (e.ColumnIndex != 0) { return; } var brush = (e.State & DataGridViewElementStates.Selected) == DataGridViewElementStates.Selected ? _selectionBrush : Brushes.White; e.Graphics.FillRectangle(brush, e.CellBounds); Rectangle srcRect = DrawGraph(e.RowIndex); if (!srcRect.IsEmpty) { e.Graphics.DrawImage ( _graphBitmap, e.CellBounds, srcRect, GraphicsUnit.Pixel ); } e.Handled = true; } }
// end drawGraph private bool DrawItem(Graphics wa, Graph.ILaneRow row) { if (row == null || row.NodeLane == -1) { return(false); } // Clip to the area we're drawing in, but draw 1 pixel past so // that the top/bottom of the line segment's anti-aliasing isn't // visible in the final rendering. int top = wa.RenderingOrigin.Y + _rowHeight / 2; var laneRect = new Rectangle(0, top, Width, _rowHeight); Region oldClip = wa.Clip; var newClip = new Region(laneRect); newClip.Intersect(oldClip); wa.Clip = newClip; wa.Clear(Color.Transparent); //for (int r = 0; r < 2; r++) for (int lane = 0; lane < row.Count; lane++) { int mid = wa.RenderingOrigin.X + (int)((lane + 0.5) * _laneWidth); for (int item = 0; item < row.LaneInfoCount(lane); item++) { Graph.LaneInfo laneInfo = row[lane, item]; bool highLight = (RevisionGraphDrawStyle == RevisionGraphDrawStyleEnum.DrawNonRelativesGray && laneInfo.Junctions.Any(j => j.IsRelative)) || (RevisionGraphDrawStyle == RevisionGraphDrawStyleEnum.HighlightSelected && laneInfo.Junctions.Any(j => j.HighLight)) || (RevisionGraphDrawStyle == RevisionGraphDrawStyleEnum.Normal); List <Color> curColors = GetJunctionColors(laneInfo.Junctions); // Create the brush for drawing the line Brush brushLineColor = null; Pen brushLineColorPen = null; try { bool drawBorder = Settings.BranchBorders && highLight; //hide border for "non-relatives" if (curColors.Count == 1 || !Settings.StripedBranchChange) { if (curColors[0] != _nonRelativeColor) { brushLineColor = new SolidBrush(curColors[0]); } else if (curColors.Count > 1 && curColors[1] != _nonRelativeColor) { brushLineColor = new SolidBrush(curColors[1]); } else { drawBorder = false; brushLineColor = new SolidBrush(_nonRelativeColor); } } else { Color lastRealColor = curColors.LastOrDefault(c => c != _nonRelativeColor); if (lastRealColor.IsEmpty) { brushLineColor = new SolidBrush(_nonRelativeColor); drawBorder = false; } else { brushLineColor = new HatchBrush(HatchStyle.DarkDownwardDiagonal, curColors[0], lastRealColor); } } for (int i = drawBorder ? 0 : 2; i < 3; i++) { Pen penLine = null; if (i == 0) { penLine = _whiteBorderPen; } else if (i == 1) { penLine = _blackBorderPen; } else { if (brushLineColorPen == null) { brushLineColorPen = new Pen(brushLineColor, _laneLineWidth); } penLine = brushLineColorPen; } if (laneInfo.ConnectLane == lane) { wa.DrawLine ( penLine, new Point(mid, top - 1), new Point(mid, top + _rowHeight + 2) ); } else { wa.DrawBezier ( penLine, new Point(mid, top - 1), new Point(mid, top + _rowHeight + 2), new Point(mid + (laneInfo.ConnectLane - lane) * _laneWidth, top - 1), new Point(mid + (laneInfo.ConnectLane - lane) * _laneWidth, top + _rowHeight + 2) ); } } } finally { if (brushLineColorPen != null) { ((IDisposable)brushLineColorPen).Dispose(); } if (brushLineColor != null) { ((IDisposable)brushLineColor).Dispose(); } } } } // Reset the clip region wa.Clip = oldClip; { // Draw node var nodeRect = new Rectangle ( wa.RenderingOrigin.X + (_laneWidth - _nodeDimension) / 2 + row.NodeLane * _laneWidth, wa.RenderingOrigin.Y + (_rowHeight - _nodeDimension) / 2, _nodeDimension, _nodeDimension ); Brush nodeBrush; List <Color> nodeColors = GetJunctionColors(row.Node.Ancestors); bool highlight = (RevisionGraphDrawStyle == RevisionGraphDrawStyleEnum.DrawNonRelativesGray && row.Node.Ancestors.Any(j => j.IsRelative)) || (RevisionGraphDrawStyle == RevisionGraphDrawStyleEnum.HighlightSelected && row.Node.Ancestors.Any(j => j.HighLight)) || (RevisionGraphDrawStyle == RevisionGraphDrawStyleEnum.Normal); bool drawBorder = Settings.BranchBorders && highlight; if (nodeColors.Count == 1) { nodeBrush = new SolidBrush(highlight ? nodeColors[0] : _nonRelativeColor); if (nodeColors[0] == _nonRelativeColor) { drawBorder = false; } } else { nodeBrush = new LinearGradientBrush(nodeRect, nodeColors[0], nodeColors[1], LinearGradientMode.Horizontal); if (nodeColors.All(c => c == _nonRelativeColor)) { drawBorder = false; } } if (_filterMode == FilterType.Highlight && row.Node.IsFiltered) { Rectangle highlightRect = nodeRect; highlightRect.Inflate(2, 3); wa.FillRectangle(Brushes.Yellow, highlightRect); wa.DrawRectangle(Pens.Black, highlightRect); } if (row.Node.Data == null) { wa.FillEllipse(Brushes.White, nodeRect); using (var pen = new Pen(Color.Red, 2)) { wa.DrawEllipse(pen, nodeRect); } } else if (row.Node.IsActive) { wa.FillRectangle(nodeBrush, nodeRect); nodeRect.Inflate(1, 1); using (var pen = new Pen(Color.Black, 3)) wa.DrawRectangle(pen, nodeRect); } else if (row.Node.IsSpecial) { wa.FillRectangle(nodeBrush, nodeRect); if (drawBorder) { wa.DrawRectangle(Pens.Black, nodeRect); } } else { wa.FillEllipse(nodeBrush, nodeRect); if (drawBorder) { wa.DrawEllipse(Pens.Black, nodeRect); } } } return(true); }
private bool DrawItem(Graphics wa, Graph.ILaneRow row) { if (row == null || row.NodeLane == -1) { return(false); } // Clip to the area we're drawing in, but draw 1 pixel past so // that the top/bottom of the line segment's anti-aliasing isn't // visible in the final rendering. int top = wa.RenderingOrigin.Y + (_rowHeight / 2); var laneRect = new Rectangle(0, top, Width, _rowHeight); Region oldClip = wa.Clip; var newClip = new Region(laneRect); newClip.Intersect(oldClip); wa.Clip = newClip; wa.Clear(Color.Transparent); // Getting RevisionGraphDrawStyle results in call to AppSettings. This is not very cheap, cache. _revisionGraphDrawStyleCache = RevisionGraphDrawStyle; ////for (int r = 0; r < 2; r++) for (int lane = 0; lane < row.Count; lane++) { int mid = wa.RenderingOrigin.X + (int)((lane + 0.5) * _laneWidth); for (int item = 0; item < row.LaneInfoCount(lane); item++) { Graph.LaneInfo laneInfo = row[lane, item]; bool highLight = (_revisionGraphDrawStyleCache == RevisionGraphDrawStyleEnum.DrawNonRelativesGray && laneInfo.Junctions.Any(j => j.IsRelative)) || (_revisionGraphDrawStyleCache == RevisionGraphDrawStyleEnum.HighlightSelected && laneInfo.Junctions.Any(j => j.HighLight)) || (_revisionGraphDrawStyleCache == RevisionGraphDrawStyleEnum.Normal); List <Color> curColors = GetJunctionColors(laneInfo.Junctions); // Create the brush for drawing the line Brush brushLineColor = null; Pen brushLineColorPen = null; try { bool drawBorder = highLight && AppSettings.BranchBorders; // hide border for "non-relatives" if (curColors.Count == 1 || !AppSettings.StripedBranchChange) { if (curColors[0] != _nonRelativeColor) { brushLineColor = new SolidBrush(curColors[0]); } else if (curColors.Count > 1 && curColors[1] != _nonRelativeColor) { brushLineColor = new SolidBrush(curColors[1]); } else { drawBorder = false; brushLineColor = new SolidBrush(_nonRelativeColor); } } else { Color lastRealColor = curColors.LastOrDefault(c => c != _nonRelativeColor); if (lastRealColor.IsEmpty) { brushLineColor = new SolidBrush(_nonRelativeColor); drawBorder = false; } else { brushLineColor = new HatchBrush(HatchStyle.DarkDownwardDiagonal, curColors[0], lastRealColor); } } // Precalculate line endpoints bool singleLane = laneInfo.ConnectLane == lane; int x0 = mid; int y0 = top - 1; int x1 = singleLane ? x0 : mid + ((laneInfo.ConnectLane - lane) * _laneWidth); int y1 = top + _rowHeight; Point p0 = new Point(x0, y0); Point p1 = new Point(x1, y1); // Precalculate curve control points when needed Point c0, c1; if (singleLane) { c0 = c1 = Point.Empty; } else { // Controls the curvature of cross-lane lines (0 = straight line, 1 = 90 degree turns) const float severity = 0.5f; c0 = new Point(x0, (int)((y0 * (1.0f - severity)) + (y1 * severity))); c1 = new Point(x1, (int)((y1 * (1.0f - severity)) + (y0 * severity))); } for (int i = drawBorder ? 0 : 2; i < 3; i++) { Pen penLine; switch (i) { case 0: penLine = _whiteBorderPen; break; case 1: penLine = _blackBorderPen; break; default: if (brushLineColorPen == null) { brushLineColorPen = new Pen(brushLineColor, _laneLineWidth); } penLine = brushLineColorPen; break; } if (singleLane) { wa.DrawLine(penLine, p0, p1); } else { wa.DrawBezier(penLine, p0, c0, c1, p1); } } } finally { brushLineColorPen?.Dispose(); ((IDisposable)brushLineColor)?.Dispose(); } } } // Reset the clip region wa.Clip = oldClip; { // Draw node var nodeRect = new Rectangle( wa.RenderingOrigin.X + ((_laneWidth - _nodeDimension) / 2) + (row.NodeLane * _laneWidth), wa.RenderingOrigin.Y + ((_rowHeight - _nodeDimension) / 2), _nodeDimension, _nodeDimension); Brush nodeBrush; List <Color> nodeColors = GetJunctionColors(row.Node.Ancestors); bool highlight = (_revisionGraphDrawStyleCache == RevisionGraphDrawStyleEnum.DrawNonRelativesGray && row.Node.Ancestors.Any(j => j.IsRelative)) || (_revisionGraphDrawStyleCache == RevisionGraphDrawStyleEnum.HighlightSelected && row.Node.Ancestors.Any(j => j.HighLight)) || (_revisionGraphDrawStyleCache == RevisionGraphDrawStyleEnum.Normal); bool drawBorder = AppSettings.BranchBorders && highlight; if (nodeColors.Count == 1) { nodeBrush = new SolidBrush(highlight ? nodeColors[0] : _nonRelativeColor); if (nodeColors[0] == _nonRelativeColor) { drawBorder = false; } } else { nodeBrush = new LinearGradientBrush(nodeRect, nodeColors[0], nodeColors[1], LinearGradientMode.Horizontal); if (nodeColors.All(c => c == _nonRelativeColor)) { drawBorder = false; } } if (_filterMode == FilterType.Highlight && row.Node.IsFiltered) { Rectangle highlightRect = nodeRect; highlightRect.Inflate(2, 3); wa.FillRectangle(Brushes.Yellow, highlightRect); wa.DrawRectangle(Pens.Black, highlightRect); } if (row.Node.Data == null) { wa.FillEllipse(Brushes.White, nodeRect); using (var pen = new Pen(Color.Red, 2)) { wa.DrawEllipse(pen, nodeRect); } } else if (row.Node.IsActive) { wa.FillRectangle(nodeBrush, nodeRect); nodeRect.Inflate(1, 1); using (var pen = new Pen(Color.Black, 3)) { wa.DrawRectangle(pen, nodeRect); } } else if (row.Node.IsSpecial) { wa.FillRectangle(nodeBrush, nodeRect); if (drawBorder) { wa.DrawRectangle(Pens.Black, nodeRect); } } else { wa.FillEllipse(nodeBrush, nodeRect); if (drawBorder) { wa.DrawEllipse(Pens.Black, nodeRect); } } } return(true); }
// end drawGraph private bool DrawItem(Graphics wa, Graph.ILaneRow row) { if (row == null || row.NodeLane == -1) { return(false); } // Clip to the area we're drawing in, but draw 1 pixel past so // that the top/bottom of the line segment's anti-aliasing isn't // visible in the final rendering. int top = wa.RenderingOrigin.Y + rowHeight / 2; var laneRect = new Rectangle(0, top, Width, rowHeight); Region oldClip = wa.Clip; var newClip = new Region(laneRect); newClip.Intersect(oldClip); wa.Clip = newClip; wa.Clear(Color.Transparent); for (int r = 0; r < 2; r++) { for (int lane = 0; lane < row.Count; lane++) { int mid = wa.RenderingOrigin.X + (int)((lane + 0.5) * LANE_WIDTH); for (int item = 0; item < row.LaneInfoCount(lane); item++) { Graph.LaneInfo laneInfo = row[lane, item]; //Draw all non-relative items first, them draw //all relative items on top if (laneInfo.Junctions.FirstOrDefault() != null) { if (laneInfo.Junctions.First().IsRelative == (r == 0)) { continue; } } List <Color> curColors = GetJunctionColors(laneInfo.Junctions); // Create the brush for drawing the line Brush brushLineColor; bool drawBorder = Settings.BranchBorders; //hide border for "non-relatives" if (curColors.Count == 1 || !Settings.StripedBranchChange) { if (curColors[0] != nonRelativeColor) { brushLineColor = new SolidBrush(curColors[0]); } else if (curColors.Count > 1 && curColors[1] != nonRelativeColor) { brushLineColor = new SolidBrush(curColors[1]); } else { drawBorder = false; brushLineColor = new SolidBrush(nonRelativeColor); } } else { brushLineColor = new HatchBrush(HatchStyle.DarkDownwardDiagonal, curColors[0], curColors[1]); if (curColors[0] == nonRelativeColor && curColors[1] == nonRelativeColor) { drawBorder = false; } } for (int i = drawBorder ? 0 : 2; i < 3; i++) { Pen penLine; if (i == 0) { penLine = new Pen(new SolidBrush(Color.White), LANE_LINE_WIDTH + 2); } else if (i == 1) { penLine = new Pen(new SolidBrush(Color.Black), LANE_LINE_WIDTH + 1); } else { penLine = new Pen(brushLineColor, LANE_LINE_WIDTH); } if (laneInfo.ConnectLane == lane) { wa.DrawLine ( penLine, new Point(mid, top - 1), new Point(mid, top + rowHeight + 2) ); } else { wa.DrawBezier ( penLine, new Point(mid, top - 1), new Point(mid, top + rowHeight + 2), new Point(mid + (laneInfo.ConnectLane - lane) * LANE_WIDTH, top - 1), new Point(mid + (laneInfo.ConnectLane - lane) * LANE_WIDTH, top + rowHeight + 2) ); } } } } } // Reset the clip region wa.Clip = oldClip; { // Draw node var nodeRect = new Rectangle ( wa.RenderingOrigin.X + (LANE_WIDTH - NODE_DIMENSION) / 2 + row.NodeLane * LANE_WIDTH, wa.RenderingOrigin.Y + (rowHeight - NODE_DIMENSION) / 2, NODE_DIMENSION, NODE_DIMENSION ); Brush nodeBrush; bool drawBorder = Settings.BranchBorders; List <Color> nodeColors = GetJunctionColors(row.Node.Ancestors); if (nodeColors.Count == 1) { nodeBrush = new SolidBrush(nodeColors[0]); if (nodeColors[0] == nonRelativeColor) { drawBorder = false; } } else { nodeBrush = new LinearGradientBrush(nodeRect, nodeColors[0], nodeColors[1], LinearGradientMode.Horizontal); if (nodeColors[0] == nonRelativeColor && nodeColors[1] == Color.LightGray) { drawBorder = false; } } if (filterMode == FilterType.Highlight && row.Node.IsFiltered) { Rectangle highlightRect = nodeRect; highlightRect.Inflate(2, 3); wa.FillRectangle(Brushes.Yellow, highlightRect); wa.DrawRectangle(new Pen(Brushes.Black), highlightRect); } if (row.Node.Data == null) { wa.FillEllipse(Brushes.White, nodeRect); wa.DrawEllipse(new Pen(Color.Red, 2), nodeRect); } else if (row.Node.IsActive) { wa.FillRectangle(nodeBrush, nodeRect); nodeRect.Inflate(1, 1); wa.DrawRectangle(new Pen(Color.Black, 3), nodeRect); } else if (row.Node.IsSpecial) { wa.FillRectangle(nodeBrush, nodeRect); if (drawBorder) { wa.DrawRectangle(new Pen(Color.Black, 1), nodeRect); } } else { wa.FillEllipse(nodeBrush, nodeRect); if (drawBorder) { wa.DrawEllipse(new Pen(Color.Black, 1), nodeRect); } } } return(true); }
private bool DrawItem(Graphics wa, Graph.ILaneRow row) { ThreadHelper.AssertOnUIThread(); if (row == null || row.NodeLane == -1) { return(false); } // Clip to the area we're drawing in, but draw 1 pixel past so // that the top/bottom of the line segment's anti-aliasing isn't // visible in the final rendering. int top = wa.RenderingOrigin.Y + (_rowHeight / 2); var laneRect = new Rectangle(0, top, Width, _rowHeight); Region oldClip = wa.Clip; var newClip = new Region(laneRect); newClip.Intersect(oldClip); wa.Clip = newClip; wa.Clear(Color.Transparent); // Getting RevisionGraphDrawStyle results in call to AppSettings. This is not very cheap, cache. _revisionGraphDrawStyleCache = RevisionGraphDrawStyle; ////for (int r = 0; r < 2; r++) for (int lane = 0; lane < row.Count; lane++) { int mid = wa.RenderingOrigin.X + (int)((lane + 0.5) * _laneWidth); for (int item = 0; item < row.LaneInfoCount(lane); item++) { Graph.LaneInfo laneInfo = row[lane, item]; bool highLight = (_revisionGraphDrawStyleCache == RevisionGraphDrawStyleEnum.DrawNonRelativesGray && laneInfo.Junctions.Any(j => j.IsRelative)) || (_revisionGraphDrawStyleCache == RevisionGraphDrawStyleEnum.HighlightSelected && laneInfo.Junctions.Any(j => j.HighLight)) || (_revisionGraphDrawStyleCache == RevisionGraphDrawStyleEnum.Normal); UpdateJunctionColors(laneInfo.Junctions); // Create the brush for drawing the line Brush lineBrush = null; Pen linePen = null; try { bool drawBorder = highLight && AppSettings.BranchBorders; // hide border for "non-relatives" if (_junctionColors.Count == 1 || !AppSettings.StripedBranchChange) { if (_junctionColors[0] != _nonRelativeColor) { lineBrush = new SolidBrush(_junctionColors[0]); } else if (_junctionColors.Count > 1 && _junctionColors[1] != _nonRelativeColor) { lineBrush = new SolidBrush(_junctionColors[1]); } else { drawBorder = false; lineBrush = new SolidBrush(_nonRelativeColor); } } else { Color lastRealColor = _junctionColors.LastOrDefault(c => c != _nonRelativeColor); if (lastRealColor.IsEmpty) { lineBrush = new SolidBrush(_nonRelativeColor); drawBorder = false; } else { lineBrush = new HatchBrush(HatchStyle.DarkDownwardDiagonal, _junctionColors[0], lastRealColor); } } // Precalculate line endpoints bool sameLane = laneInfo.ConnectLane == lane; int x0 = mid; int y0 = top - 1; int x1 = sameLane ? x0 : mid + ((laneInfo.ConnectLane - lane) * _laneWidth); int y1 = top + _rowHeight; Point p0 = new Point(x0, y0); Point p1 = new Point(x1, y1); // Precalculate curve control points when needed Point c0, c1; if (sameLane) { // We are drawing between two points in the same // lane, so there will be no curve c0 = c1 = default; } else { // Left shifting int is fast equivalent of dividing by two, // thus computing the average of y0 and y1. var yMid = (y0 + y1) >> 1; c0 = new Point(x0, yMid); c1 = new Point(x1, yMid); } for (int i = drawBorder ? 0 : 2; i < 3; i++) { Pen pen; switch (i) { case 0: pen = _whiteBorderPen; break; case 1: pen = _blackBorderPen; break; default: if (linePen == null) { linePen = new Pen(lineBrush, _laneLineWidth); } pen = linePen; break; } if (sameLane) { wa.DrawLine(pen, p0, p1); } else { wa.DrawBezier(pen, p0, c0, c1, p1); } } } finally { linePen?.Dispose(); lineBrush?.Dispose(); } } } // Reset the clip region wa.Clip = oldClip; // Draw node var nodeRect = new Rectangle( wa.RenderingOrigin.X + ((_laneWidth - _nodeDimension) / 2) + (row.NodeLane * _laneWidth), wa.RenderingOrigin.Y + ((_rowHeight - _nodeDimension) / 2), _nodeDimension, _nodeDimension); Brush nodeBrush; UpdateJunctionColors(row.Node.Ancestors); bool highlight = (_revisionGraphDrawStyleCache == RevisionGraphDrawStyleEnum.DrawNonRelativesGray && row.Node.Ancestors.Any(j => j.IsRelative)) || (_revisionGraphDrawStyleCache == RevisionGraphDrawStyleEnum.HighlightSelected && row.Node.Ancestors.Any(j => j.HighLight)) || (_revisionGraphDrawStyleCache == RevisionGraphDrawStyleEnum.Normal); bool drawNodeBorder = AppSettings.BranchBorders && highlight; if (_junctionColors.Count == 1) { nodeBrush = new SolidBrush(highlight ? _junctionColors[0] : _nonRelativeColor); if (_junctionColors[0] == _nonRelativeColor) { drawNodeBorder = false; } } else { nodeBrush = new LinearGradientBrush( nodeRect, _junctionColors[0], _junctionColors[1], LinearGradientMode.Horizontal); if (_junctionColors.All(c => c == _nonRelativeColor)) { drawNodeBorder = false; } } if (row.Node.Data == null) { wa.FillEllipse(Brushes.White, nodeRect); using (var pen = new Pen(Color.Red, 2)) { wa.DrawEllipse(pen, nodeRect); } } else if (row.Node.IsActive) { wa.FillRectangle(nodeBrush, nodeRect); nodeRect.Inflate(1, 1); using (var pen = new Pen(Color.Black, 3)) { wa.DrawRectangle(pen, nodeRect); } } else if (row.Node.IsSpecial) { wa.FillRectangle(nodeBrush, nodeRect); if (drawNodeBorder) { wa.DrawRectangle(Pens.Black, nodeRect); } } else { wa.FillEllipse(nodeBrush, nodeRect); if (drawNodeBorder) { wa.DrawEllipse(Pens.Black, nodeRect); } } nodeBrush.Dispose(); return(true); void UpdateJunctionColors(IEnumerable <Junction> junction) { _junctionColors.Clear(); // Color of non-relative branches. _junctionColors.AddRange(junction.Select(GetJunctionColor)); if (_junctionColors.Count == 0) { _junctionColors.Add(Color.Black); } } }
private Rectangle drawGraph(int aNeededRow) { lock (graphData) { if (aNeededRow < 0 || graphData.Count == 0 || graphData.Count <= aNeededRow) { return(Rectangle.Empty); } #region Make sure the graph cache bitmap is setup int height = cacheCountMax * rowHeight; int width = dataGridColumnGraph.Width; if (graphBitmap == null || //Resize the bitmap when the with or height is changed. The height won't change very often. //The with changes more often, when branches become visible/invisible. //Try to be 'smart' and not resize the bitmap for each little change. Enlarge when needed //but never shrink the bitmap since the huge performance hit is worse than the little extra memory. graphBitmap.Width < width || graphBitmap.Height != height) { if (graphBitmap != null) { graphBitmap.Dispose(); graphBitmap = null; } if (width > 0 && height > 0) { graphBitmap = new Bitmap(Math.Max(width, LANE_WIDTH * 3), height, PixelFormat.Format32bppPArgb); graphWorkArea = Graphics.FromImage(graphBitmap); graphWorkArea.SmoothingMode = SmoothingMode.AntiAlias; cacheHead = 0; cacheCount = 0; } else { return(Rectangle.Empty); } } #endregion // Compute how much the head needs to move to show the requested item. int neededHeadAdjustment = aNeededRow - cacheHead; if (neededHeadAdjustment > 0) { neededHeadAdjustment -= cacheCountMax - 1; if (neededHeadAdjustment < 0) { neededHeadAdjustment = 0; } } int newRows = 0; if (cacheCount < cacheCountMax) { newRows = (aNeededRow - cacheCount) + 1; } // Adjust the head of the cache cacheHead = cacheHead + neededHeadAdjustment; cacheHeadRow = (cacheHeadRow + neededHeadAdjustment) % cacheCountMax; if (cacheHeadRow < 0) { cacheHeadRow = cacheCountMax + cacheHeadRow; } int start; int end; if (newRows > 0) { start = cacheHead + cacheCount; cacheCount = Math.Min(cacheCount + newRows, cacheCountMax); end = cacheHead + cacheCount; } else if (neededHeadAdjustment > 0) { end = cacheHead + cacheCount; start = Math.Max(cacheHead, end - neededHeadAdjustment); } else if (neededHeadAdjustment < 0) { start = cacheHead; end = start + Math.Min(cacheCountMax, -neededHeadAdjustment); } else { // Item already in the cache return(CreateRectangle(aNeededRow, width)); } if (RevisionGraphVisible) { for (int rowIndex = start; rowIndex < end; rowIndex++) { Graph.ILaneRow row = graphData[rowIndex]; if (row == null) { // This shouldn't be happening...If it does, clear the cache so we // eventually pick it up. Console.WriteLine("Draw lane {0} {1}", rowIndex, "NO DATA"); clearDrawCache(); return(Rectangle.Empty); } Region oldClip = graphWorkArea.Clip; // Get the x,y value of the current item's upper left in the cache int curCacheRow = (cacheHeadRow + rowIndex - cacheHead) % cacheCountMax; int x = 0; int y = curCacheRow * rowHeight; var laneRect = new Rectangle(0, y, Width, rowHeight); if (rowIndex == start || curCacheRow == 0) { // Draw previous row first. Clip top to row. We also need to clear the area // before we draw since nothing else would clear the top 1/2 of the item to draw. graphWorkArea.RenderingOrigin = new Point(x, y - rowHeight); var newClip = new Region(laneRect); graphWorkArea.Clip = newClip; graphWorkArea.Clear(Color.Transparent); drawItem(graphWorkArea, graphData[rowIndex - 1]); graphWorkArea.Clip = oldClip; } bool isLast = (rowIndex == end - 1); if (isLast) { var newClip = new Region(laneRect); graphWorkArea.Clip = newClip; } graphWorkArea.RenderingOrigin = new Point(x, y); bool success = drawItem(graphWorkArea, row); graphWorkArea.Clip = oldClip; if (!success) { clearDrawCache(); return(Rectangle.Empty); } } } return(CreateRectangle(aNeededRow, width)); } // end lock }