DrawLabel ( DrawingContext drawingContext, GraphDrawingContext graphDrawingContext, VertexDrawingHistory vertexDrawingHistory, FormattedText formattedText, Color formattedTextColor ) { Debug.Assert(drawingContext != null); Debug.Assert(graphDrawingContext != null); Debug.Assert(vertexDrawingHistory != null); Debug.Assert(formattedText != null); AssertValid(); DrawLabel(drawingContext, graphDrawingContext, vertexDrawingHistory, GetLabelPosition(vertexDrawingHistory.Vertex), formattedText, formattedTextColor, true); }
TryGetVertexDrawingHistory ( IVertex oVertex, out VertexDrawingHistory oVertexDrawingHistory ) { Debug.Assert(oVertex != null); oVertexDrawingHistory = null; Object oVertexDrawingHistoryAsObject; if (!oVertex.TryGetValue(ReservedMetadataKeys.VertexDrawingHistory, typeof(VertexDrawingHistory), out oVertexDrawingHistoryAsObject)) { return(false); } oVertexDrawingHistory = (VertexDrawingHistory)oVertexDrawingHistoryAsObject; return(true); }
TryGetVertexInformation ( IVertex oVertex1, IVertex oVertex2, out VertexDrawingHistory oVertex1DrawingHistory, out VertexDrawingHistory oVertex2DrawingHistory, out Point oEdgeEndpoint1, out Point oEdgeEndpoint2 ) { Debug.Assert(oVertex1 != null); Debug.Assert(oVertex2 != null); AssertValid(); oVertex1DrawingHistory = oVertex2DrawingHistory = null; oEdgeEndpoint1 = oEdgeEndpoint2 = new Point(); // Retrieve the information about how the vertices were drawn. if ( !TryGetVertexDrawingHistory(oVertex1, out oVertex1DrawingHistory) || !TryGetVertexDrawingHistory(oVertex2, out oVertex2DrawingHistory) ) { // One of the edge's vertices is hidden. return (false); } // The drawing histories determine the edge endpoints. For example, if // oVertex1 was drawn as a circle, then oVertex1DrawingHistory is a // CircleVertexDrawingHistory that knows to put its endpoint on the // circle itself and not at the circle's center. oVertex1DrawingHistory.GetEdgeEndpoint( oVertex2DrawingHistory.VertexLocation, out oEdgeEndpoint1); oVertex2DrawingHistory.GetEdgeEndpoint( oVertex1DrawingHistory.VertexLocation, out oEdgeEndpoint2); return (true); }
FilterIntermediatePoints ( IEdge oEdge, VertexDrawingHistory oVertex1DrawingHistory, VertexDrawingHistory oVertex2DrawingHistory ) { Debug.Assert(oEdge != null); Debug.Assert(oVertex1DrawingHistory != null); Debug.Assert(oVertex2DrawingHistory != null); AssertValid(); List<Point> oFilteredIntermediatePoints = new List<Point>(); System.Drawing.PointF [] aoIntermediateCurvePoints; DrawingVisual oVertex1DrawingVisual = oVertex1DrawingHistory.DrawingVisual; DrawingVisual oVertex2DrawingVisual = oVertex2DrawingHistory.DrawingVisual; if ( EdgeUtil.TryGetIntermediateCurvePoints(oEdge, out aoIntermediateCurvePoints) ) { foreach (System.Drawing.PointF oIntermediateCurvePoint in aoIntermediateCurvePoints) { Point oIntermediateCurveWpfPoint = WpfGraphicsUtil.PointFToWpfPoint(oIntermediateCurvePoint); // Check whether the point falls within the bounds of either // vertex. // // This could be done more quickly but with more code by // selectively hit-testing only vertex 1 or vertex 2 as we move // along the curve. However, the hit-testing is so fast that // it's probably not worth the extra complexity. On one test // machine, for example, 200,000 hit tests took about 24 ms, // and that didn't vary much with vertex shape or size. if ( oVertex1DrawingVisual.HitTest( oIntermediateCurveWpfPoint) == null && oVertex2DrawingVisual.HitTest( oIntermediateCurveWpfPoint) == null ) { oFilteredIntermediatePoints.Add( oIntermediateCurveWpfPoint); } } } return (oFilteredIntermediatePoints); }
DrawCurveThroughIntermediatePoints ( IEdge oEdge, GraphDrawingContext oGraphDrawingContext, DrawingContext oDrawingContext, VertexDrawingHistory oVertex1DrawingHistory, VertexDrawingHistory oVertex2DrawingHistory, Point oEdgeEndpoint1, Point oEdgeEndpoint2, Pen oPen ) { Debug.Assert(oEdge != null); Debug.Assert(oGraphDrawingContext != null); Debug.Assert(oDrawingContext != null); Debug.Assert(oVertex1DrawingHistory != null); Debug.Assert(oVertex2DrawingHistory != null); Debug.Assert(oPen != null); AssertValid(); // Note: Don't attempt to draw an arrow in this case. // Create a list of intermediate points, excluding those that fall // within the vertex bounds. An edge always terminates on the vertex // bounds, so we don't want it venturing into the vertex itself. List<Point> oCurvePoints = FilterIntermediatePoints(oEdge, oVertex1DrawingHistory, oVertex2DrawingHistory); Int32 iCurvePoints = oCurvePoints.Count; if (iCurvePoints == 0) { // Just draw a straight line. oDrawingContext.DrawLine(oPen, oEdgeEndpoint1, oEdgeEndpoint2); return; } #if false // Draw intermediate points for testing. foreach (Point oPoint in oCurvePoints) { oDrawingContext.DrawEllipse(Brushes.Green, null, oPoint, 2, 2); } #endif // The endpoints were originally calculated as if the edge was a // straight line between the two vertices. Recalculate them so they // connect more smoothly to the adjacent intermediate curve points. oVertex1DrawingHistory.GetEdgeEndpoint(oCurvePoints[0], out oEdgeEndpoint1); oVertex2DrawingHistory.GetEdgeEndpoint(oCurvePoints[iCurvePoints - 1], out oEdgeEndpoint2); oCurvePoints.Insert(0, oEdgeEndpoint1); oCurvePoints.Add(oEdgeEndpoint2); PathGeometry oCurveThroughPoints = WpfPathGeometryUtil.GetCurveThroughPoints(oCurvePoints, 0.5, CurveThroughIntermediatePointsTolerance); oDrawingContext.DrawGeometry(null, oPen, oCurveThroughPoints); // Note: Don't attempt to draw a label in this case. }
PostDrawVertex ( VertexShape vertexShape, Color vertexColor, GraphDrawingContext graphDrawingContext, DrawingContext drawingContext, Boolean drawAsSelected, Double graphScale, VertexLabelDrawer vertexLabelDrawer, FormattedTextManager formattedTextManager, VertexDrawingHistory vertexDrawingHistory ) { Debug.Assert(graphDrawingContext != null); Debug.Assert(drawingContext != null); Debug.Assert(graphScale >= GraphDrawer.MinimumGraphScale); Debug.Assert(graphScale <= GraphDrawer.MaximumGraphScale); Debug.Assert(vertexLabelDrawer != null); Debug.Assert(formattedTextManager != null); Debug.Assert(vertexDrawingHistory != null); AssertValid(); if (m_oCollapsedGroupVertex == null) { // The vertex that was drawn is not a collapsed group vertex. Do // nothing. return; } if (m_oCollapsedGroupAttributes.Count == 0) { // The vertex that was drawn represents a collapsed group, but no // attributes were specified for it. By default, such a vertex // gets a plus sign drawn on top of it. DrawPlusSign(vertexShape, vertexColor, graphDrawingContext, drawingContext, graphScale, vertexLabelDrawer, formattedTextManager, vertexDrawingHistory); } else { // Check whether this this is a collapsed motif. switch ( m_oCollapsedGroupAttributes.GetGroupType() ) { case CollapsedGroupAttributeValues.FanMotifType: DrawFanMotifFan(vertexColor, drawingContext, drawAsSelected, graphScale, vertexDrawingHistory); break; default: // Do nothing. This includes the D-connector motif case, // which requires no post-drawing action. break; } } }
DrawFanMotifFan ( Color oHeadColor, DrawingContext oDrawingContext, Boolean bDrawAsSelected, Double dGraphScale, VertexDrawingHistory oVertexDrawingHistory ) { Debug.Assert(oDrawingContext != null); Debug.Assert(dGraphScale >= GraphDrawer.MinimumGraphScale); Debug.Assert(dGraphScale <= GraphDrawer.MaximumGraphScale); Debug.Assert(oVertexDrawingHistory != null); AssertValid(); // The fill color to use for the fan was set in PreDrawVertex(). Object oFanColorAsObject; if ( !m_oCollapsedGroupVertex.TryGetValue( ReservedMetadataKeys.FanMotifFanColor, typeof(System.Drawing.Color), out oFanColorAsObject) ) { return; } // If the collapsed group vertex is selected, the entire vertex, // including the fan drawn here, should be drawn using oHeadColor, // which the caller has set to the selected color. Color oFanColor = bDrawAsSelected ? oHeadColor : WpfGraphicsUtil.ColorToWpfColor( (System.Drawing.Color)oFanColorAsObject); Double dAngleRadians = GetFanMotifAngleRadians(); Rect oVertexBounds = oVertexDrawingHistory.GetBounds().Bounds; Brush oFillBrush = new SolidColorBrush(oFanColor); WpfGraphicsUtil.FreezeIfFreezable(oFillBrush); Color oPenColor = GetCollapsedMotifOutlineColor(255); Brush oPenBrush = new SolidColorBrush(oPenColor); WpfGraphicsUtil.FreezeIfFreezable(oPenBrush); Pen oPen = new Pen(oPenBrush, 2.0 * dGraphScale); WpfGraphicsUtil.FreezeIfFreezable(oPen); oDrawingContext.DrawGeometry( oFillBrush, oPen, GetCircleSegment(oVertexBounds, dAngleRadians, dGraphScale) ); }
DrawPlusSign ( VertexShape eVertexShape, Color oVertexColor, GraphDrawingContext oGraphDrawingContext, DrawingContext oDrawingContext, Double dGraphScale, VertexLabelDrawer oVertexLabelDrawer, FormattedTextManager oFormattedTextManager, VertexDrawingHistory oVertexDrawingHistory ) { Debug.Assert(oGraphDrawingContext != null); Debug.Assert(oDrawingContext != null); Debug.Assert(dGraphScale >= GraphDrawer.MinimumGraphScale); Debug.Assert(dGraphScale <= GraphDrawer.MaximumGraphScale); Debug.Assert(oVertexLabelDrawer != null); Debug.Assert(oFormattedTextManager != null); Debug.Assert(oVertexDrawingHistory != null); AssertValid(); Color oFillColor; switch (eVertexShape) { case VertexShape.Circle: case VertexShape.Square: case VertexShape.Diamond: case VertexShape.Triangle: // The fill color is the color of the background. Adjust the // fill color for the opacity of the vertex. oFillColor = WpfGraphicsUtil.SetWpfColorAlpha( oGraphDrawingContext.BackColor, oVertexColor.A); break; default: oFillColor = oVertexColor; break; } Color oContrastingColor = WpfGraphicsUtil.GetContrastingColor(oFillColor); // The font size used below was chosen so that it is large enough to be // easily readable, but small enough to fit within the smallest // collapsed group vertex created by this class. oVertexLabelDrawer.DrawLabel(oDrawingContext, oGraphDrawingContext, oVertexDrawingHistory, VertexLabelPosition.MiddleCenter, oFormattedTextManager.CreateFormattedText("+", oContrastingColor, 15.0, dGraphScale), oContrastingColor, false); }
DrawLabel ( DrawingContext drawingContext, GraphDrawingContext graphDrawingContext, VertexDrawingHistory vertexDrawingHistory, VertexLabelPosition labelPosition, FormattedText formattedText, Color formattedTextColor, Boolean drawBackground ) { Debug.Assert(drawingContext != null); Debug.Assert(graphDrawingContext != null); Debug.Assert(vertexDrawingHistory != null); Debug.Assert(formattedText != null); AssertValid(); if (labelPosition == VertexLabelPosition.Nowhere) { return; } // The alignment needs to be set before the width and height of the // FormattedText are obtained. SetTextAlignment(formattedText, labelPosition); // You can't use FormattedText.Width to get the width of the actual // text when text wrapping is enabled (FormattedText.MaxTextWidth > 0). // Instead, use a method that takes wrapping into account. Double dLabelWidth = WpfGraphicsUtil.GetFormattedTextSize( formattedText).Width; Double dLabelHeight = formattedText.Height; // This is the point where the label will be drawn using // DrawingContext.Draw(). It initially assumes a text height of zero, // a margin of zero, and no adjustment for alignment (see // dAdjustmentForTextAlignmentX below), but this will be modified // appropriately within the switch statement below. Point oDraw = vertexDrawingHistory.GetLabelLocation(labelPosition); Double dDrawX = oDraw.X; Double dDrawY = oDraw.Y; // These are the left and right bounds of the rectangle where the text // will actually appear. Double dLabelBoundsLeft = 0; Double dLabelBoundsRight = 0; AdjustForTextAlignment(dLabelWidth, dLabelHeight, labelPosition, formattedText, ref dDrawX, ref dDrawY, ref dLabelBoundsLeft, ref dLabelBoundsRight); // Don't let the text exceed the bounds of the graph rectangle. dDrawX = StayWithinHorizontalBounds( dDrawX, graphDrawingContext, dLabelBoundsLeft, dLabelBoundsRight); Double dLabelBoundsTop = dDrawY; Double dLabelBoundsBottom = dDrawY + dLabelHeight; dDrawY = StayWithinVerticalBounds( dDrawY, graphDrawingContext, dLabelBoundsTop, dLabelBoundsBottom); if (drawBackground) { dLabelBoundsLeft = StayWithinHorizontalBounds( dLabelBoundsLeft, graphDrawingContext, dLabelBoundsLeft, dLabelBoundsRight); DrawLabelBackground(drawingContext, graphDrawingContext, formattedText, formattedTextColor, m_btBackgroundAlpha, new Point(dLabelBoundsLeft, dDrawY)); } drawingContext.DrawText(formattedText, new Point(dDrawX, dDrawY)); }
TryGetVertexDrawingHistory ( IVertex oVertex, out VertexDrawingHistory oVertexDrawingHistory ) { Debug.Assert(oVertex != null); oVertexDrawingHistory = null; Object oVertexDrawingHistoryAsObject; if ( !oVertex.TryGetValue(ReservedMetadataKeys.VertexDrawingHistory, typeof(VertexDrawingHistory), out oVertexDrawingHistoryAsObject) ) { return (false); } oVertexDrawingHistory = (VertexDrawingHistory)oVertexDrawingHistoryAsObject; return (true); }
DrawLabel ( DrawingContext drawingContext, GraphDrawingContext graphDrawingContext, VertexDrawingHistory vertexDrawingHistory, FormattedText formattedText, Color formattedTextColor ) { Debug.Assert(drawingContext != null); Debug.Assert(graphDrawingContext != null); Debug.Assert(vertexDrawingHistory != null); Debug.Assert(formattedText != null); AssertValid(); DrawLabel(drawingContext, graphDrawingContext, vertexDrawingHistory, GetLabelPosition(vertexDrawingHistory.Vertex), formattedText, formattedTextColor, true); }
DrawLabel ( DrawingContext drawingContext, GraphDrawingContext graphDrawingContext, VertexDrawingHistory vertexDrawingHistory, VertexLabelPosition labelPosition, FormattedText formattedText, Color formattedTextColor, Boolean drawBackground ) { Debug.Assert(drawingContext != null); Debug.Assert(graphDrawingContext != null); Debug.Assert(vertexDrawingHistory != null); Debug.Assert(formattedText != null); AssertValid(); if (labelPosition == VertexLabelPosition.Nowhere) { return; } // The alignment needs to be set before the width and height of the // FormattedText are obtained. SetTextAlignment(formattedText, labelPosition); // You can't use FormattedText.Width to get the width of the actual // text when text wrapping is enabled (FormattedText.MaxTextWidth > 0). // Instead, use a method that takes wrapping into account. Double dLabelWidth = WpfGraphicsUtil.GetFormattedTextSize( formattedText).Width; Double dLabelHeight = formattedText.Height; // This is the point where the label will be drawn using // DrawingContext.Draw(). It initially assumes a text height of zero, // a margin of zero, and no adjustment for alignment (see // dAdjustmentForTextAlignmentX below), but this will be modified // appropriately within the switch statement below. Point oDraw = vertexDrawingHistory.GetLabelLocation(labelPosition); Double dDrawX = oDraw.X; Double dDrawY = oDraw.Y; // These are the left and right bounds of the rectangle where the text // will actually appear. Double dLabelBoundsLeft = 0; Double dLabelBoundsRight = 0; AdjustForTextAlignment(dLabelWidth, dLabelHeight, labelPosition, formattedText, ref dDrawX, ref dDrawY, ref dLabelBoundsLeft, ref dLabelBoundsRight); // Don't let the text exceed the bounds of the graph rectangle. dDrawX = StayWithinHorizontalBounds( dDrawX, graphDrawingContext, dLabelBoundsLeft, dLabelBoundsRight); Double dLabelBoundsTop = dDrawY; Double dLabelBoundsBottom = dDrawY + dLabelHeight; dDrawY = StayWithinVerticalBounds( dDrawY, graphDrawingContext, dLabelBoundsTop, dLabelBoundsBottom); if (drawBackground) { dLabelBoundsLeft = StayWithinHorizontalBounds( dLabelBoundsLeft, graphDrawingContext, dLabelBoundsLeft, dLabelBoundsRight); DrawLabelBackground( drawingContext, graphDrawingContext, formattedText, formattedTextColor, m_btBackgroundAlpha, new Point(dLabelBoundsLeft, dDrawY) ); } drawingContext.DrawText( formattedText, new Point(dDrawX, dDrawY) ); }
TryDrawVertex ( IVertex vertex, GraphDrawingContext graphDrawingContext, out VertexDrawingHistory vertexDrawingHistory ) { AssertValid(); vertexDrawingHistory = null; CheckDrawVertexArguments(vertex, graphDrawingContext); if (graphDrawingContext.GraphRectangleMinusMarginIsEmpty) { return (false); } // If the vertex is hidden, do nothing. VisibilityKeyValue eVisibility = GetVisibility(vertex); if (eVisibility == VisibilityKeyValue.Hidden) { return (false); } // Check whether the vertex represents a collapsed group and perform // collapsed group tasks if necessary. CollapsedGroupDrawingManager oCollapsedGroupDrawingManager = new CollapsedGroupDrawingManager(); oCollapsedGroupDrawingManager.PreDrawVertex(vertex); // Check for a per-vertex label. Object oLabelAsObject; String sLabel = null; if ( vertex.TryGetValue(ReservedMetadataKeys.PerVertexLabel, typeof(String), out oLabelAsObject) ) { sLabel = (String)oLabelAsObject; if ( String.IsNullOrEmpty(sLabel) ) { sLabel = null; } else { sLabel = TruncateLabel(sLabel); } } Boolean bDrawAsSelected = GetDrawAsSelected(vertex); Point oLocation = WpfGraphicsUtil.PointFToWpfPoint(vertex.Location); DrawingVisualPlus oDrawingVisual = new DrawingVisualPlus(); VertexShape eShape = GetShape(vertex); VertexLabelDrawer oVertexLabelDrawer = new VertexLabelDrawer(m_eLabelPosition, m_btBackgroundAlpha); using ( DrawingContext oDrawingContext = oDrawingVisual.RenderOpen() ) { if (eShape == VertexShape.Label) { if (sLabel != null) { // Draw the vertex as a label. vertexDrawingHistory = DrawLabelShape(vertex, graphDrawingContext, oDrawingContext, oDrawingVisual, eVisibility, bDrawAsSelected, sLabel, oCollapsedGroupDrawingManager); } else { // Default to something usable. eShape = VertexShape.Disk; } } else if (eShape == VertexShape.Image) { Object oImageSourceAsObject; if (vertex.TryGetValue(ReservedMetadataKeys.PerVertexImage, typeof(ImageSource), out oImageSourceAsObject) ) { // Draw the vertex as an image. vertexDrawingHistory = DrawImageShape(vertex, graphDrawingContext, oDrawingContext, oDrawingVisual, eVisibility, bDrawAsSelected, sLabel, (ImageSource)oImageSourceAsObject, oVertexLabelDrawer, oCollapsedGroupDrawingManager); } else { // Default to something usable. eShape = VertexShape.Disk; } } if (vertexDrawingHistory == null) { // Draw the vertex as a simple shape. vertexDrawingHistory = DrawSimpleShape(vertex, eShape, graphDrawingContext, oDrawingContext, oDrawingVisual, eVisibility, bDrawAsSelected, sLabel, oVertexLabelDrawer, oCollapsedGroupDrawingManager); } // Perform collapsed group tasks if necessary. oCollapsedGroupDrawingManager.PostDrawVertex(eShape, GetColor(vertex, eVisibility, bDrawAsSelected), graphDrawingContext, oDrawingContext, bDrawAsSelected, m_dGraphScale, oVertexLabelDrawer, m_oFormattedTextManager, vertexDrawingHistory); } return (true); }