示例#1
0
 public void Replace(int aOld, int aNew)
 {
     for (int j = edges.CountNext(aOld) - 1; j >= 0; --j)
     {
         Graph.LaneInfo info = edges.RemoveNext(aOld, j, out var start, out _);
         info.ConnectLane = aNew;
         edges.Add(start, info);
     }
 }
示例#2
0
 public void Replace(int old, int @new)
 {
     for (int j = _edges.CountNext(old) - 1; j >= 0; --j)
     {
         Graph.LaneInfo info = _edges.RemoveNext(old, j, out var start, out _);
         info.ConnectLane = @new;
         _edges.Add(start, info);
     }
 }
                public void Expand(int col)
                {
                    int edgeCount = Math.Max(_edges.CountCurrent(), _edges.CountNext());

                    for (int i = edgeCount - 1; i >= col; --i)
                    {
                        while (_edges.CountNext(i) > 0)
                        {
                            Graph.LaneInfo info = _edges.RemoveNext(i, 0, out var start, out _);
                            info.ConnectLane++;
                            _edges.Add(start, info);
                        }
                    }
                }
                public void Collapse(int col)
                {
                    int edgeCount = Math.Max(_edges.CountCurrent(), _edges.CountNext());

                    for (int i = col; i < edgeCount; i++)
                    {
                        while (_edges.CountNext(i) > 0)
                        {
                            Graph.LaneInfo info = _edges.RemoveNext(i, 0, out var start, out _);
                            info.ConnectLane--;
                            _edges.Add(start, info);
                        }
                    }
                }
示例#5
0
                public void Expand(int col)
                {
                    int edgeCount = Math.Max(edges.CountCurrent(), edges.CountNext());

                    for (int i = edgeCount - 1; i >= col; --i)
                    {
                        while (edges.CountNext(i) > 0)
                        {
                            int            start, end;
                            Graph.LaneInfo info = edges.RemoveNext(i, 0, out start, out end);
                            info.ConnectLane++;
                            edges.Add(start, info);
                        }
                    }
                }
示例#6
0
                public void Collapse(int col)
                {
                    int edgeCount = Math.Max(edges.CountCurrent(), edges.CountNext());

                    for (int i = col; i < edgeCount; i++)
                    {
                        while (edges.CountNext(i) > 0)
                        {
                            int            start, end;
                            Graph.LaneInfo info = edges.RemoveNext(i, 0, out start, out end);
                            info.ConnectLane--;
                            edges.Add(start, info);
                        }
                    }
                }
示例#7
0
                    public void Add(int from, Graph.LaneInfo data)
                    {
                        var e = new Edge(data, from);

                        edges.Add(e);

                        while (countStart.Count <= e.Start)
                        {
                            countStart.Add(0);
                        }
                        countStart[e.Start]++;
                        while (countEnd.Count <= e.End)
                        {
                            countEnd.Add(0);
                        }
                        countEnd[e.End]++;
                    }
示例#8
0
                public Graph.ILaneRow Advance()
                {
                    var newLaneRow = new SavedLaneRow(this);

                    var newEdges = new Edges();

                    for (int i = 0; i < edges.CountNext(); i++)
                    {
                        int edgeCount = edges.CountNext(i);
                        if (edgeCount > 0)
                        {
                            Graph.LaneInfo info = edges.Next(i, 0).Clone();
                            for (int j = 1; j < edgeCount; j++)
                            {
                                Graph.LaneInfo edgeInfo = edges.Next(i, j);
                                info.UnionWith(edgeInfo);
                            }
                            newEdges.Add(i, info);
                        }
                    }
                    edges = newEdges;

                    return(newLaneRow);
                }
示例#9
0
        // 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);
        }
示例#10
0
        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);
        }
示例#11
0
 public Edge(Graph.LaneInfo data, int start)
 {
     Data  = data;
     Start = start;
 }
示例#12
0
 public void Add(int lane, Graph.LaneInfo data)
 {
     edges.Add(lane, data);
 }
示例#13
0
            private bool MoveNext()
            {
                // If there are no lanes, there is nothing more to draw
                if (laneNodes.Count == 0 || sourceGraph.Count <= laneRows.Count)
                {
                    return(false);
                }

                // Find the new current row's node (newest item in the row)

                #region Find current node & index

                currentRow.Node = null;
                for (int curLane = 0; curLane < laneNodes.Count; curLane++)
                {
                    LaneJunctionDetail lane = laneNodes[curLane];
                    if (lane.Count == 0)
                    {
                        continue;
                    }

                    // NOTE: We could also compare with sourceGraph sourceGraph.AddedNodes[sourceGraph.processedNodes],
                    // since it should always be the same value
                    if (currentRow.Node == null ||
                        currentRow.Node.Data == null ||
                        (lane.Current.Data != null && lane.Current.Index < currentRow.Node.Index))
                    {
                        currentRow.Node     = lane.Current;
                        currentRow.NodeLane = curLane;
                        //break;
                    }
                }
                if (currentRow.Node == null)
                {
                    // DEBUG: The check above didn't find anything, but should have
                    if (Debugger.IsAttached)
                    {
                        Debugger.Break();
                    }
                    //Node[] topo = this.sourceGraph.TopoSortedNodes();
                    return(false);
                }

                // If this row doesn't contain data, we're to the end of the valid entries.
                if (currentRow.Node.Data == null)
                {
                    return(false);
                }

                sourceGraph.ProcessNode(currentRow.Node);

                #endregion

                // Check for multiple junctions with this node at the top. Remove the
                // node from that junction as well. This will happen when there is a branch

                #region Check for branches

                currentRow.Clear(currentRow.NodeLane);
                for (int curLane = 0; curLane < laneNodes.Count; curLane++)
                {
                    LaneJunctionDetail lane = laneNodes[curLane];
                    if (lane.Count == 0)
                    {
                        continue;
                    }

                    if (currentRow.Node != lane.Current)
                    {
                        // We're only interested in columns that have the same node
                        // at the top of the junction as the current row's node
                        continue;
                    }

                    // Remove the item from the lane, since it is being drawn now.
                    // We need to draw the graph line for this lane. If there are no items
                    // left in the lane we don't draw it.
                    int intoLane = AdvanceLane(curLane);
                    if (intoLane < curLane)
                    {
                        // AdvanceLane could have removed lanes so we need to start from
                        // the merged into lane (otherwise we could skip a lane, causing
                        // us to try to insert a node into the graph twice)
                        curLane = intoLane;
                    }

                    // Re-process the lane to make sure there are no actions left.
                    curLane--;
                }

                #endregion

                // Look for lanes that cross and reorder to straighten them out if possible,
                // and keep the lanes that merge next to each other.

                #region Straighten out lanes

                // Look for crossing lanes
                //   but only when there are not too many lanes taking up too much performance
                if (currentRow.Count < 10)
                {
                    for (int lane = 0; lane < currentRow.Count; lane++)
                    {
                        for (int item = 0; item < currentRow.LaneInfoCount(lane); item++)
                        {
                            Graph.LaneInfo laneInfo = currentRow[lane, item];
                            if (laneInfo.ConnectLane <= lane)
                            {
                                continue;
                            }
                            // Lane is moving to the right, check to see if it intersects
                            // with any lanes moving to the left.
                            for (int otherLane = lane + 1; otherLane <= laneInfo.ConnectLane; otherLane++)
                            {
                                if (currentRow.LaneInfoCount(otherLane) != 1)
                                {
                                    continue;
                                }
                                Graph.LaneInfo otherLaneInfo = currentRow[otherLane, 0];
                                if (otherLaneInfo.ConnectLane < otherLane)
                                {
                                    currentRow.Swap(otherLaneInfo.ConnectLane, otherLane);
                                    LaneJunctionDetail temp = laneNodes[otherLane];
                                    laneNodes[otherLane] = laneNodes[otherLaneInfo.ConnectLane];
                                    laneNodes[otherLaneInfo.ConnectLane] = temp;
                                }
                            }
                        }
                    }
                }

                //// Keep the merge lanes next to each other
                //int mergeFromCount = currentRow.LaneInfoCount(currentRow.NodeLane);
                //if (mergeFromCount > 1)
                //{
                //    for (int i = 0; i < mergeFromCount; i++)
                //    {
                //        Graph.LaneInfo laneInfo = currentRow[currentRow.NodeLane, i];
                //        // Check to see if the lane is currently next to us
                //        if (laneInfo.ConnectLane - currentRow.NodeLane > mergeFromCount)
                //        {
                //            // Only move the lane if it isn't already being drawn.
                //            if (currentRow.LaneInfoCount(laneInfo.ConnectLane) == 0)
                //            {
                //                // Remove the row laneInfo.ConnectLane and insert
                //                // it at currentRow.NodeLane+1.
                //                // Then start over searching for others if i != mergeFromCount-1?
                //                int adjacentLane = currentRow.NodeLane + 1;
                //                if (adjacentLane >= laneNodes.Count) Debugger.Break();
                //                currentRow.Expand(adjacentLane);
                //                currentRow.Replace(laneInfo.ConnectLane + 1, adjacentLane);

                //                LaneJunctionDetail temp = laneNodes[laneInfo.ConnectLane];
                //                laneNodes.RemoveAt(laneInfo.ConnectLane);
                //                laneNodes.Insert(adjacentLane, temp);
                //            }
                //        }
                //    }
                //}

                #endregion

                if (currentRow.Node != null)
                {
                    Graph.ILaneRow row = currentRow.Advance();

                    // This means there is a node that got put in the graph twice...
                    if (row.Node.InLane != int.MaxValue)
                    {
                        if (Debugger.IsAttached)
                        {
                            Debugger.Break();
                        }
                    }

                    row.Node.InLane = laneRows.Count;
                    laneRows.Add(row);
                    return(true);
                }

                // Return that there are more items left
                return(false);
            }
示例#14
0
        // 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);
        }
示例#15
0
        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);
                }
            }
        }