// 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); }
// 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) { 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); }
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); } } }