GetColor ( IMetadataProvider oVertexOrEdge, VisibilityKeyValue eVisibility, Boolean bDrawAsSelected ) { Debug.Assert(oVertexOrEdge != null); AssertValid(); if (bDrawAsSelected) { Color oColor = m_oSelectedColor; if (eVisibility == VisibilityKeyValue.Filtered) { oColor.A = m_btFilteredAlpha; } return(oColor); } return(GetColor(oVertexOrEdge, eVisibility, ReservedMetadataKeys.PerColor, m_oColor, true)); }
GetAlpha ( IMetadataProvider oVertexOrEdge, VisibilityKeyValue eVisibility, Byte btDefaultAlpha ) { Debug.Assert(oVertexOrEdge != null); AssertValid(); if (eVisibility == VisibilityKeyValue.Filtered) { // The vertex or edge is filtered. return(m_btFilteredAlpha); } // Check for a per-vertex or per-edge alpha. Object oPerAlphaAsObject; if (oVertexOrEdge.TryGetValue(ReservedMetadataKeys.PerAlpha, typeof(Single), out oPerAlphaAsObject)) { Single fPerAlpha = (Single)oPerAlphaAsObject; if (fPerAlpha < 0F || fPerAlpha > 255F) { Debug.Assert(oVertexOrEdge is IIdentityProvider); throw new FormatException(String.Format( "{0}: The {1} with the ID {2} has an out-of-range" + " {3} value. Valid values are between 0 and 255." , this.ClassName, (oVertexOrEdge is IVertex) ? "vertex" : "edge", ((IIdentityProvider)oVertexOrEdge).ID, "ReservedMetadataKeys.PerAlpha" )); } return((Byte)fPerAlpha); } return(btDefaultAlpha); }
GetColor ( IMetadataProvider oVertexOrEdge, VisibilityKeyValue eVisibility, Boolean bDrawAsSelected ) { Debug.Assert(oVertexOrEdge != null); AssertValid(); if (bDrawAsSelected) { return(m_oSelectedColor); } return(GetColor(oVertexOrEdge, eVisibility, ReservedMetadataKeys.PerColor, m_oColor, true)); }
GetColor ( IMetadataProvider oVertexOrEdge, VisibilityKeyValue eVisibility, String sKey, Color oDefaultColor, Boolean bApplyAlpha ) { Debug.Assert(oVertexOrEdge != null); Debug.Assert(!String.IsNullOrEmpty(sKey)); AssertValid(); Byte btDefaultAlpha = oDefaultColor.A; // Start with the default color. Color oColor = oDefaultColor; // Check for a per-vertex or per-edge color. Color oPerColor; if (TryGetColorValue(oVertexOrEdge, sKey, out oPerColor)) { oColor = oPerColor; oColor.A = btDefaultAlpha; } if (bApplyAlpha) { // Apply the vertex or edge's alpha. oColor.A = GetAlpha(oVertexOrEdge, eVisibility, oColor.A); } return(oColor); }
TryGetEdgeVisibility ( IEdge oEdge, String sKey, out VisibilityKeyValue eVisibility ) { Debug.Assert(oEdge != null); Debug.Assert(!String.IsNullOrEmpty(sKey)); eVisibility = VisibilityKeyValue.Visible; Object oVisibilityAsObject; if (oEdge.TryGetValue(sKey, typeof(VisibilityKeyValue), out oVisibilityAsObject)) { eVisibility = (VisibilityKeyValue)oVisibilityAsObject; return(true); } return(false); }
TryGetEdgeVisibility ( IEdge oEdge, String sKey, out VisibilityKeyValue eVisibility ) { Debug.Assert(oEdge != null); Debug.Assert( !String.IsNullOrEmpty(sKey) ); eVisibility = VisibilityKeyValue.Visible; Object oVisibilityAsObject; if ( oEdge.TryGetValue(sKey, typeof(VisibilityKeyValue), out oVisibilityAsObject) ) { eVisibility = (VisibilityKeyValue)oVisibilityAsObject; return (true); } return (false); }
//************************************************************************* // Method: DrawLabelShape() // /// <summary> /// Draws a vertex as a label. /// </summary> /// /// <param name="oVertex"> /// The vertex to draw. /// </param> /// /// <param name="oGraphDrawingContext"> /// Provides access to objects needed for graph-drawing operations. /// </param> /// /// <param name="oDrawingContext"> /// The DrawingContext to use. /// </param> /// /// <param name="oDrawingVisual"> /// The <see cref="DrawingVisual" /> object from which <paramref /// name="oDrawingContext" /> was obtained. /// </param> /// /// <param name="eVisibility"> /// The visibility of the vertex. /// </param> /// /// <param name="bDrawAsSelected"> /// true to draw the vertex as selected. /// </param> /// /// <param name="sLabel"> /// The label to draw. Can't be null or empty. /// </param> /// /// <returns> /// A VertexDrawingHistory object that retains information about how the /// vertex was drawn. /// </returns> //************************************************************************* protected VertexDrawingHistory DrawLabelShape( IVertex oVertex, GraphDrawingContext oGraphDrawingContext, DrawingContext oDrawingContext, DrawingVisual oDrawingVisual, VisibilityKeyValue eVisibility, Boolean bDrawAsSelected, String sLabel ) { Debug.Assert(oVertex != null); Debug.Assert(oGraphDrawingContext != null); Debug.Assert(oDrawingContext != null); Debug.Assert(oDrawingVisual != null); Debug.Assert( !String.IsNullOrEmpty(sLabel) ); AssertValid(); // Figure out what colors to use. Color oOutlineColor; Color oTextColor = GetColor(oVertex, eVisibility, false); Color oFillColor = GetColor(oVertex, eVisibility, ReservedMetadataKeys.PerVertexLabelFillColor, m_oLabelFillColor, true); if (bDrawAsSelected) { // The outline color is always the selected color. oOutlineColor = m_oSelectedColor; // The text color is the default or per-vertex color with no alpha. oTextColor.A = 255; // The fill color is the default or per-vertex fill color with no // alpha. oFillColor.A = 255; } else { // The outline color is the default or per-vertex color with alpha. oOutlineColor = oTextColor; // The text color is the default or per-vertex color with alpha. // The fill color is the default or per-vertex fill color with // alpha. } Double dLabelFontSize = GetLabelFontSize(oVertex); // Format the text, subject to a maximum label size. If a maximum // label size isn't specified, the label would be as wide as necessary // to accommodate the text length. Specifying a maximum size forces // the text to wrap at word breaks. // // Side effect: If the font size is large enough, not a single // character of the text will fit within the specified width and no // text will be drawn. FormattedText oFormattedText = CreateFormattedText(sLabel, oTextColor, dLabelFontSize); oFormattedText.MaxTextWidth = MaximumLabelWidth * m_dGraphScale; oFormattedText.MaxTextHeight = MaximumLabelHeight * m_dGraphScale; Rect oVertexRectangle = GetVertexRectangle( GetVertexLocation(oVertex), oFormattedText.Width, oFormattedText.Height); // Pad the text. Rect oVertexRectangleWithPadding = oVertexRectangle; Double dLabelPadding = GetLabelPadding(dLabelFontSize); oVertexRectangleWithPadding.Inflate(dLabelPadding, dLabelPadding * 0.7); if (m_oTypeface.Style != FontStyles.Normal) { // This is a hack to move the right edge of the padded rectangle // to the right to adjust for wider italic text, which // FormattedText.Width does not account for. What is the correct // way to do this? It might involve the FormattedText.Overhang* // properties, but I'll be darned if I can understand how those // properties work. Double dItalicCompensation = dLabelFontSize / 7.0; oVertexRectangleWithPadding.Inflate(dItalicCompensation, 0); oVertexRectangleWithPadding.Offset(dItalicCompensation, 0); } // Move the vertex if it falls outside the graph rectangle. Double dOriginalVertexRectangleWithPaddingX = oVertexRectangleWithPadding.X; Double dOriginalVertexRectangleWithPaddingY = oVertexRectangleWithPadding.Y; MoveVertexIfNecessary(oVertex, ref oVertexRectangleWithPadding, oGraphDrawingContext); oVertexRectangle.Offset( oVertexRectangleWithPadding.X - dOriginalVertexRectangleWithPaddingX, oVertexRectangleWithPadding.Y - dOriginalVertexRectangleWithPaddingY ); // Draw the padded rectangle, then the text. oDrawingContext.DrawRectangle( GetBrush(oFillColor), GetPen(oOutlineColor, DefaultPenThickness), oVertexRectangleWithPadding); oDrawingContext.DrawText(oFormattedText, oVertexRectangle.Location); // Return information about how the vertex was drawn. return ( new LabelVertexDrawingHistory(oVertex, oDrawingVisual, bDrawAsSelected, oVertexRectangleWithPadding) ); }
DrawSimpleShape ( IVertex oVertex, VertexShape eShape, GraphDrawingContext oGraphDrawingContext, DrawingContext oDrawingContext, DrawingVisualPlus oDrawingVisual, VisibilityKeyValue eVisibility, Boolean bDrawAsSelected, String sAnnotation, VertexLabelDrawer oVertexLabelDrawer, CollapsedGroupDrawingManager oCollapsedGroupDrawingManager ) { Debug.Assert(oVertex != null); Debug.Assert(oGraphDrawingContext != null); Debug.Assert(oDrawingContext != null); Debug.Assert(oDrawingVisual != null); Debug.Assert(oVertexLabelDrawer != null); Debug.Assert(oCollapsedGroupDrawingManager != null); AssertValid(); Double dRadius = GetRadius(oVertex); Color oColor = GetColor(oVertex, eVisibility, bDrawAsSelected); Point oVertexLocation = GetVertexLocation(oVertex); oDrawingVisual.SetEffect( GetSimpleShapeEffect( oGraphDrawingContext, dRadius, oColor) ); Rect oVertexBounds; if (eShape == VertexShape.Triangle || eShape == VertexShape.SolidTriangle) { oVertexBounds = WpfGraphicsUtil.TriangleBoundsFromCenterAndHalfWidth( oVertexLocation, dRadius); } else if (eShape == VertexShape.SolidTaperedDiamond) { // Note that the bounds of a tapered diamond can't be calculated // using simple equations. Instead, create the tapered diamond and // let WPF compute the bounds. // // There is some inefficiency here, because the tapered diamond // gets created again before it is drawn, in its possibly-moved // location. oVertexBounds = WpfPathGeometryUtil.GetTaperedDiamond( oVertexLocation, dRadius).Bounds; } else if (eShape == VertexShape.SolidRoundedX) { // Note that the bounds of a rounded X can't be calculated // using simple equations. Instead, create the rounded X and // let WPF compute the bounds. // // There is some inefficiency here, because the rounded X // gets created again before it is drawn, in its possibly-moved // location. oVertexBounds = WpfPathGeometryUtil.GetRoundedX( oVertexLocation, dRadius).Bounds; } else { oVertexBounds = WpfGraphicsUtil.SquareFromCenterAndHalfWidth( oVertexLocation, dRadius); } // Move the vertex if it falls outside the graph rectangle. MoveVertexIfNecessary(oVertex, oGraphDrawingContext, oCollapsedGroupDrawingManager, ref oVertexBounds); oVertexLocation = GetVertexLocation(oVertex); VertexDrawingHistory oVertexDrawingHistory = null; // Note that for the "hollow" shapes -- Circle, Square, Diamond, and // Triangle -- Brushes.Transparent is used instead of a null brush. // This allows the entire area of these shapes to be hit-tested. Using // a null brush would cause hit-testing to fail if the shapes' // interiors were clicked. switch (eShape) { case VertexShape.Circle: case VertexShape.Disk: Boolean bIsDisk = (eShape == VertexShape.Disk); oDrawingContext.DrawEllipse( bIsDisk ? GetBrush(oColor) : Brushes.Transparent, bIsDisk ? null : GetPen(oColor, DefaultPenThickness), oVertexLocation, dRadius, dRadius ); oVertexDrawingHistory = bIsDisk ? new DiskVertexDrawingHistory( oVertex, oDrawingVisual, bDrawAsSelected, dRadius) : new CircleVertexDrawingHistory( oVertex, oDrawingVisual, bDrawAsSelected, dRadius); break; case VertexShape.Sphere: RadialGradientBrush oRadialGradientBrush = new RadialGradientBrush(); oRadialGradientBrush.GradientOrigin = oRadialGradientBrush.Center = new Point(0.3, 0.3); GradientStopCollection oGradientStops = oRadialGradientBrush.GradientStops; oGradientStops.Add( new GradientStop( WpfGraphicsUtil.SetWpfColorAlpha(Colors.White, oColor.A), 0.0) ); oGradientStops.Add( new GradientStop(oColor, 1.0) ); WpfGraphicsUtil.FreezeIfFreezable(oRadialGradientBrush); oDrawingContext.DrawEllipse(oRadialGradientBrush, null, oVertexLocation, dRadius, dRadius); oVertexDrawingHistory = new SphereVertexDrawingHistory( oVertex, oDrawingVisual, bDrawAsSelected, dRadius); break; case VertexShape.Square: WpfGraphicsUtil.DrawPixelAlignedRectangle(oDrawingContext, Brushes.Transparent, GetPen(oColor, DefaultPenThickness), oVertexBounds); oVertexDrawingHistory = new SquareVertexDrawingHistory(oVertex, oDrawingVisual, bDrawAsSelected, oVertexBounds); break; case VertexShape.SolidSquare: oDrawingContext.DrawRectangle(GetBrush(oColor), null, oVertexBounds); oVertexDrawingHistory = new SolidSquareVertexDrawingHistory( oVertex, oDrawingVisual, bDrawAsSelected, oVertexBounds); break; case VertexShape.Diamond: case VertexShape.SolidDiamond: Boolean bIsSolidDiamond = (eShape == VertexShape.SolidDiamond); PathGeometry oDiamond = WpfPathGeometryUtil.GetDiamond(oVertexLocation, dRadius); oDrawingContext.DrawGeometry( bIsSolidDiamond ? GetBrush(oColor) : Brushes.Transparent, bIsSolidDiamond ? null : GetPen(oColor, DefaultPenThickness), oDiamond ); oVertexDrawingHistory = bIsSolidDiamond ? new SolidDiamondVertexDrawingHistory( oVertex, oDrawingVisual, bDrawAsSelected, dRadius) : new DiamondVertexDrawingHistory( oVertex, oDrawingVisual, bDrawAsSelected, dRadius); break; case VertexShape.Triangle: case VertexShape.SolidTriangle: Boolean bIsSolidTriangle = (eShape == VertexShape.SolidTriangle); PathGeometry oTriangle = WpfPathGeometryUtil.GetTriangle(oVertexLocation, dRadius); oDrawingContext.DrawGeometry( bIsSolidTriangle ? GetBrush(oColor) : Brushes.Transparent, bIsSolidTriangle ? null : GetPen(oColor, DefaultPenThickness), oTriangle ); oVertexDrawingHistory = bIsSolidTriangle ? new SolidTriangleVertexDrawingHistory( oVertex, oDrawingVisual, bDrawAsSelected, dRadius) : new TriangleVertexDrawingHistory( oVertex, oDrawingVisual, bDrawAsSelected, dRadius); break; case VertexShape.SolidTaperedDiamond: Geometry oTaperedDiamond = WpfPathGeometryUtil.GetTaperedDiamond( oVertexLocation, dRadius); // Note that as of August 2012, the tapered diamond shape is // used only for collapsed connector motifs. Collapsed motifs // have an outline, so draw an outline here. oDrawingContext.DrawGeometry(GetBrush(oColor), GetPen( CollapsedGroupDrawingManager .GetCollapsedMotifOutlineColor(oColor.A), DefaultPenThickness), oTaperedDiamond); oVertexDrawingHistory = new SolidTaperedDiamondVertexDrawingHistory( oVertex, oDrawingVisual, bDrawAsSelected, dRadius); break; case VertexShape.SolidRoundedX: Geometry oRoundedX = WpfPathGeometryUtil.GetRoundedX( oVertexLocation, dRadius); // Note that as of August 2012, the rounded X shape is // used only for collapsed clique motifs. Collapsed motifs // have an outline, so draw an outline here. oDrawingContext.DrawGeometry(GetBrush(oColor), GetPen(CollapsedGroupDrawingManager .GetCollapsedMotifOutlineColor(oColor.A), DefaultPenThickness), oRoundedX); oVertexDrawingHistory = new SolidRoundedXVertexDrawingHistory( oVertex, oDrawingVisual, bDrawAsSelected, dRadius); break; default: Debug.Assert(false); break; } if (sAnnotation != null) { oVertexLabelDrawer.DrawLabel(oDrawingContext, oGraphDrawingContext, oVertexDrawingHistory, CreateFormattedTextWithWrap(sAnnotation, oColor, m_oFormattedTextManager.FontSize), oColor); } Debug.Assert(oVertexDrawingHistory != null); return (oVertexDrawingHistory); }
DrawStraightEdge ( IEdge oEdge, GraphDrawingContext oGraphDrawingContext, DrawingContext oDrawingContext, Point oEdgeEndpoint1, Point oEdgeEndpoint2, Boolean bDrawAsSelected, Boolean bDrawArrow, Pen oPen, Color oColor, Double dWidth, VisibilityKeyValue eVisibility, String sLabel ) { Debug.Assert(oEdge != null); Debug.Assert(oGraphDrawingContext != null); Debug.Assert(oDrawingContext != null); Debug.Assert(oPen != null); AssertValid(); if (bDrawArrow) { // Draw the arrow and set the second endpoint to the center of the // flat end of the arrow. Double dArrowAngle = WpfGraphicsUtil.GetAngleBetweenPointsRadians( oEdgeEndpoint1, oEdgeEndpoint2); oEdgeEndpoint2 = DrawArrow(oDrawingContext, oEdgeEndpoint2, dArrowAngle, oColor, dWidth); } oDrawingContext.DrawLine(oPen, oEdgeEndpoint1, oEdgeEndpoint2); if ( !String.IsNullOrEmpty(sLabel) ) { DrawLabel(oEdge, oDrawingContext, oGraphDrawingContext, bDrawAsSelected, oColor, eVisibility, oEdgeEndpoint1, oEdgeEndpoint2, null, new Point(), sLabel); } }
GetColor ( IMetadataProvider oVertexOrEdge, VisibilityKeyValue eVisibility, String sKey, Color oDefaultColor, Boolean bApplyAlpha ) { Debug.Assert(oVertexOrEdge != null); Debug.Assert( !String.IsNullOrEmpty(sKey) ); AssertValid(); Byte btDefaultAlpha = oDefaultColor.A; // Start with the default color. Color oColor = oDefaultColor; // Check for a per-vertex or per-edge color. Color oPerColor; if ( TryGetColorValue(oVertexOrEdge, sKey, out oPerColor) ) { oColor = oPerColor; oColor.A = btDefaultAlpha; } if (bApplyAlpha) { // Apply the vertex or edge's alpha. oColor.A = GetAlpha(oVertexOrEdge, eVisibility, oColor.A); } return (oColor); }
GetAlpha ( IMetadataProvider oVertexOrEdge, VisibilityKeyValue eVisibility, Byte btDefaultAlpha ) { Debug.Assert(oVertexOrEdge != null); AssertValid(); if (eVisibility == VisibilityKeyValue.Filtered) { // The vertex or edge is filtered. return (m_btFilteredAlpha); } // Check for a per-vertex or per-edge alpha. Object oPerAlphaAsObject; if ( oVertexOrEdge.TryGetValue(ReservedMetadataKeys.PerAlpha, typeof(Single), out oPerAlphaAsObject) ) { Single fPerAlpha = (Single)oPerAlphaAsObject; if (fPerAlpha < 0F || fPerAlpha > 255F) { Debug.Assert(oVertexOrEdge is IIdentityProvider); throw new FormatException( String.Format( "{0}: The {1} with the ID {2} has an out-of-range" + " {3} value. Valid values are between 0 and 255." , this.ClassName, (oVertexOrEdge is IVertex) ? "vertex" : "edge", ( (IIdentityProvider)oVertexOrEdge ).ID, "ReservedMetadataKeys.PerAlpha" ) ); } return ( (Byte)fPerAlpha ); } return (btDefaultAlpha); }
GetColor ( IMetadataProvider oVertexOrEdge, VisibilityKeyValue eVisibility, Boolean bDrawAsSelected ) { Debug.Assert(oVertexOrEdge != null); AssertValid(); if (bDrawAsSelected) { Color oColor = m_oSelectedColor; if (eVisibility == VisibilityKeyValue.Filtered) { oColor.A = m_btFilteredAlpha; } return (oColor); } return ( GetColor(oVertexOrEdge, eVisibility, ReservedMetadataKeys.PerColor, m_oColor, true) ); }
//************************************************************************* // Method: GetColor() // /// <overloads> /// Gets the color of a vertex or edge. /// </overloads> /// /// <summary> /// Gets the color of a vertex or edge. /// </summary> /// /// <param name="oVertexOrEdge"> /// The vertex or edge to get the color for. /// </param> /// /// <param name="eVisibility"> /// The visibility of the vertex or edge. This can be obtained with <see /// cref="GetVisibility" />. /// </param> /// /// <param name="bDrawAsSelected"> /// true if <paramref name="oVertexOrEdge" /> should be drawn as selected. /// </param> /// /// <returns> /// The color of the vertex or edge. This includes any per-vertex or /// per-edge alpha value specified on the vertex or edge, along with the /// visibility specified by <paramref name="eVisibility" />. /// </returns> //************************************************************************* protected Color GetColor( IMetadataProvider oVertexOrEdge, VisibilityKeyValue eVisibility, Boolean bDrawAsSelected ) { Debug.Assert(oVertexOrEdge != null); AssertValid(); if (bDrawAsSelected) { return (m_oSelectedColor); } return ( GetColor(oVertexOrEdge, eVisibility, ReservedMetadataKeys.PerColor, m_oColor, true) ); }
TryDrawEdge ( IEdge edge, GraphDrawingContext graphDrawingContext, out EdgeDrawingHistory edgeDrawingHistory ) { Debug.Assert(edge != null); Debug.Assert(graphDrawingContext != null); AssertValid(); edgeDrawingHistory = null; // If the edge is hidden, do nothing. VisibilityKeyValue eVisibility = GetVisibility(edge); if (eVisibility == VisibilityKeyValue.Hidden) { return(false); } Boolean bDrawAsSelected = GetDrawAsSelected(edge); Color oColor = GetColor(edge, eVisibility, bDrawAsSelected); Double dWidth = GetWidth(edge, bDrawAsSelected); DashStyle oDashStyle = GetDashStyle(edge, dWidth, bDrawAsSelected); Boolean bDrawArrow = (m_bDrawArrowOnDirectedEdge && edge.IsDirected); IVertex [] aoVertices = edge.Vertices; DrawingVisual oDrawingVisual = new DrawingVisual(); using (DrawingContext oDrawingContext = oDrawingVisual.RenderOpen()) { if (edge.IsSelfLoop) { if (!TryDrawSelfLoop(aoVertices[0], oDrawingContext, graphDrawingContext, oColor, dWidth, bDrawArrow)) { // The edge's vertex is hidden, so the edge should be // hidden also. return(false); } } else { Point oEdgeEndpoint1, oEdgeEndpoint2; if (!TryGetEdgeEndpoints(aoVertices[0], aoVertices[1], graphDrawingContext, out oEdgeEndpoint1, out oEdgeEndpoint2)) { // One of the edge's vertices is hidden, so the edge should // be hidden also. return(false); } if (bDrawArrow) { // Draw the arrow and set the second endpoint to the center // of the flat end of the arrow. Double dArrowAngle = WpfGraphicsUtil.GetAngleBetweenPoints( oEdgeEndpoint1, oEdgeEndpoint2); oEdgeEndpoint2 = DrawArrow(oDrawingContext, oEdgeEndpoint2, dArrowAngle, oColor, dWidth); } // Draw the edge. oDrawingContext.DrawLine(GetPen(oColor, dWidth, oDashStyle), oEdgeEndpoint1, oEdgeEndpoint2); // Draw the edge's label, if there is one. Object oLabelAsObject; if (edge.TryGetValue(ReservedMetadataKeys.PerEdgeLabel, typeof(String), out oLabelAsObject) && oLabelAsObject != null) { DrawLabel(oDrawingContext, graphDrawingContext, oEdgeEndpoint1, oEdgeEndpoint2, (String)oLabelAsObject, oColor); } } // Retain information about the edge that was drawn. edgeDrawingHistory = new EdgeDrawingHistory( edge, oDrawingVisual, bDrawAsSelected); return(true); } }
GetLabelTextColor ( IEdge oEdge, Boolean bDrawAsSelected, Color oEdgeColor, VisibilityKeyValue eVisibility ) { Debug.Assert(oEdge != null); AssertValid(); Color oLabelTextColor; if (bDrawAsSelected) { // The edge color was calculated using the selected state. oLabelTextColor = oEdgeColor; } else { oLabelTextColor = GetColor(oEdge, eVisibility, ReservedMetadataKeys.PerEdgeLabelTextColor, m_oLabelTextColor, false); oLabelTextColor = WpfGraphicsUtil.SetWpfColorAlpha(oLabelTextColor, oEdgeColor.A); } return (oLabelTextColor); }
//************************************************************************* // Method: DrawSimpleShape() // /// <summary> /// Draws a vertex as a simple shape. /// </summary> /// /// <param name="oVertex"> /// The vertex to draw. /// </param> /// /// <param name="eShape"> /// The vertex shape to use. Can't be <see cref="VertexShape.Image" /> or /// <see cref="VertexShape.Label" />. /// </param> /// /// <param name="oGraphDrawingContext"> /// Provides access to objects needed for graph-drawing operations. /// </param> /// /// <param name="oDrawingContext"> /// The DrawingContext to use. /// </param> /// /// <param name="oDrawingVisual"> /// The <see cref="DrawingVisual" /> object from which <paramref /// name="oDrawingContext" /> was obtained. /// </param> /// /// <param name="eVisibility"> /// The visibility of the vertex. /// </param> /// /// <param name="bDrawAsSelected"> /// true to draw the vertex as selected. /// </param> /// /// <param name="sAnnotation"> /// The annotation to draw next to the shape, or null if there is no /// annotation. /// </param> /// /// <param name="oVertexLabelDrawer"> /// Object that draws a vertex label as an annotation. /// </param> /// /// <returns> /// A VertexDrawingHistory object that retains information about how the /// vertex was drawn. /// </returns> /// /// <remarks> /// "Simple" means "not <see cref="VertexShape.Image" /> and not <see /// cref="VertexShape.Label" />." /// </remarks> //************************************************************************* protected VertexDrawingHistory DrawSimpleShape( IVertex oVertex, VertexShape eShape, GraphDrawingContext oGraphDrawingContext, DrawingContext oDrawingContext, DrawingVisual oDrawingVisual, VisibilityKeyValue eVisibility, Boolean bDrawAsSelected, String sAnnotation, VertexLabelDrawer oVertexLabelDrawer ) { Debug.Assert(oVertex != null); Debug.Assert(oGraphDrawingContext != null); Debug.Assert(oDrawingContext != null); Debug.Assert(oDrawingVisual != null); Debug.Assert(oVertexLabelDrawer != null); AssertValid(); Double dRadius = GetRadius(oVertex); Color oColor = GetColor(oVertex, eVisibility, bDrawAsSelected); Point oVertexLocation = GetVertexLocation(oVertex); Rect oVertexBounds; if (eShape == VertexShape.Triangle || eShape == VertexShape.SolidTriangle) { oVertexBounds = WpfGraphicsUtil.TriangleBoundsFromCenterAndHalfWidth( oVertexLocation, dRadius); } else { oVertexBounds = WpfGraphicsUtil.SquareFromCenterAndHalfWidth( oVertexLocation, dRadius); } // Move the vertex if it falls outside the graph rectangle. MoveVertexIfNecessary(oVertex, ref oVertexBounds, oGraphDrawingContext); Point oLocation = GetVertexLocation(oVertex); VertexDrawingHistory oVertexDrawingHistory = null; // Note that for the "hollow" shapes -- Circle, Square, Diamond, and // Triangle -- Brushes.Transparent is used instead of a null brush. // This allows the entire area of these shapes to be hit-tested. Using // a null brush would cause hit-testing to fail if the shapes' // interiors were clicked. switch (eShape) { case VertexShape.Circle: case VertexShape.Disk: Boolean bIsDisk = (eShape == VertexShape.Disk); oDrawingContext.DrawEllipse( bIsDisk ? GetBrush(oColor) : Brushes.Transparent, bIsDisk ? null : GetPen(oColor, DefaultPenThickness), oLocation, dRadius, dRadius ); oVertexDrawingHistory = bIsDisk ? new DiskVertexDrawingHistory( oVertex, oDrawingVisual, bDrawAsSelected, dRadius) : new CircleVertexDrawingHistory( oVertex, oDrawingVisual, bDrawAsSelected, dRadius); break; case VertexShape.Sphere: RadialGradientBrush oRadialGradientBrush = new RadialGradientBrush(); oRadialGradientBrush.GradientOrigin = oRadialGradientBrush.Center = new Point(0.3, 0.3); GradientStopCollection oGradientStops = oRadialGradientBrush.GradientStops; oGradientStops.Add( new GradientStop(Colors.White, 0.0) ); oGradientStops.Add( new GradientStop(oColor, 1.0) ); WpfGraphicsUtil.FreezeIfFreezable(oRadialGradientBrush); oDrawingContext.DrawEllipse(oRadialGradientBrush, null, oLocation, dRadius, dRadius); oVertexDrawingHistory = new SphereVertexDrawingHistory( oVertex, oDrawingVisual, bDrawAsSelected, dRadius); break; case VertexShape.Square: case VertexShape.SolidSquare: Boolean bIsSolidSquare = (eShape == VertexShape.SolidSquare); oDrawingContext.DrawRectangle( bIsSolidSquare ? GetBrush(oColor) : Brushes.Transparent, bIsSolidSquare? null : GetPen(oColor, DefaultPenThickness), oVertexBounds ); oVertexDrawingHistory = bIsSolidSquare ? new SolidSquareVertexDrawingHistory(oVertex, oDrawingVisual, bDrawAsSelected, oVertexBounds) : new SquareVertexDrawingHistory(oVertex, oDrawingVisual, bDrawAsSelected, oVertexBounds); break; case VertexShape.Diamond: case VertexShape.SolidDiamond: Boolean bIsSolidDiamond = (eShape == VertexShape.SolidDiamond); PathGeometry oDiamond = WpfGraphicsUtil.DiamondFromCenterAndHalfWidth( oLocation, dRadius); oDrawingContext.DrawGeometry( bIsSolidDiamond ? GetBrush(oColor) : Brushes.Transparent, bIsSolidDiamond ? null : GetPen(oColor, DefaultPenThickness), oDiamond ); oVertexDrawingHistory = bIsSolidDiamond ? new SolidDiamondVertexDrawingHistory( oVertex, oDrawingVisual, bDrawAsSelected, dRadius) : new DiamondVertexDrawingHistory( oVertex, oDrawingVisual, bDrawAsSelected, dRadius); break; case VertexShape.Triangle: case VertexShape.SolidTriangle: Boolean bIsSolidTriangle = (eShape == VertexShape.SolidTriangle); PathGeometry oTriangle = WpfGraphicsUtil.TriangleFromCenterAndHalfWidth( oLocation, dRadius); oDrawingContext.DrawGeometry( bIsSolidTriangle ? GetBrush(oColor) : Brushes.Transparent, bIsSolidTriangle ? null : GetPen(oColor, DefaultPenThickness), oTriangle ); oVertexDrawingHistory = bIsSolidTriangle ? new SolidTriangleVertexDrawingHistory( oVertex, oDrawingVisual, bDrawAsSelected, dRadius) : new TriangleVertexDrawingHistory( oVertex, oDrawingVisual, bDrawAsSelected, dRadius); break; default: Debug.Assert(false); break; } if (sAnnotation != null) { oVertexLabelDrawer.DrawLabel( oDrawingContext, oGraphDrawingContext, oVertexDrawingHistory, oVertexBounds, CreateFormattedText(sAnnotation, oColor) ); } if ( oVertex.ContainsKey(ReservedMetadataKeys.PerVertexDrawPlusSign) ) { DrawPlusSign(eShape, oVertexLocation, oVertexBounds, oColor, oGraphDrawingContext, oDrawingContext, oVertexLabelDrawer, oVertexDrawingHistory); } Debug.Assert(oVertexDrawingHistory != null); return (oVertexDrawingHistory); }
DrawLabel ( IEdge oEdge, DrawingContext oDrawingContext, GraphDrawingContext oGraphDrawingContext, Boolean bDrawAsSelected, Color oEdgeColor, VisibilityKeyValue eVisibility, Point oEdgeEndpoint1, Point oEdgeEndpoint2, PathGeometry oBezierCurve, Point oBezierControlPoint, String sLabel ) { Debug.Assert(oEdge != null); Debug.Assert(oDrawingContext != null); Debug.Assert(oGraphDrawingContext != null); Debug.Assert(sLabel != null); AssertValid(); if (sLabel.Length == 0) { return; } sLabel = TruncateLabel(sLabel); Double dFontSize = GetLabelFontSize(oEdge); Color oLabelTextColor = GetLabelTextColor(oEdge, bDrawAsSelected, oEdgeColor, eVisibility); FormattedText oFormattedText = m_oFormattedTextManager.CreateFormattedText(sLabel, oLabelTextColor, dFontSize, m_dGraphScale); oFormattedText.Trimming = TextTrimming.CharacterEllipsis; // Don't let the FormattedText class break long lines when drawing // Bezier curves. DrawBezierLabel(), which draws the label // character-by-character, is unable to tell where such line breaks // occur, because FormattedText doesn't expose this information. // // For consistency, do the same when drawing straight edges. oFormattedText.MaxLineCount = sLabel.Count(c => c == '\n') + 1; // The ends of the label text are between one and two "buffer units" // from the ends of the edge. The buffer unit is the width of an // arbitrary character. Double dBufferWidth = m_oFormattedTextManager.CreateFormattedText("i", oLabelTextColor, dFontSize, m_dGraphScale).Width; Double dEdgeLength = WpfGraphicsUtil.GetDistanceBetweenPoints( oEdgeEndpoint1, oEdgeEndpoint2); Double dEdgeLengthMinusBuffers = dEdgeLength - 2 * dBufferWidth; if (dEdgeLengthMinusBuffers <= 0) { return; } // Determine where to draw the label text. Double dTextWidth = oFormattedText.Width; Double dLabelOriginAsFractionOfEdgeLength; if (dTextWidth > dEdgeLengthMinusBuffers) { // The label text should start one buffer unit from the first // endpoint, and terminate with ellipses approximately one buffer // length from the second endpoint. dLabelOriginAsFractionOfEdgeLength = dBufferWidth / dEdgeLength; oFormattedText.MaxTextWidth = dEdgeLengthMinusBuffers; } else { // The label should be centered along the edge's length. dLabelOriginAsFractionOfEdgeLength = ( (dEdgeLength - dTextWidth) / 2.0 ) / dEdgeLength; } // Note: Don't make the translucent rectangle any more opaque than the // edge, which might be translucent itself. Color oTranslucentRectangleColor = WpfGraphicsUtil.SetWpfColorAlpha( oGraphDrawingContext.BackColor, Math.Min(LabelBackgroundAlpha, oEdgeColor.A) ); if (this.ShouldDrawBezierCurve) { DrawBezierLabel(oDrawingContext, oGraphDrawingContext, oFormattedText, oEdgeEndpoint1, oEdgeEndpoint2, oBezierCurve, dLabelOriginAsFractionOfEdgeLength, dEdgeLength, dBufferWidth, oLabelTextColor, oTranslucentRectangleColor, dFontSize); } else { DrawStraightLabel(oDrawingContext, oGraphDrawingContext, oFormattedText, oEdgeEndpoint1, oEdgeEndpoint2, dLabelOriginAsFractionOfEdgeLength, dEdgeLength, dBufferWidth, oTranslucentRectangleColor); } }
//************************************************************************* // Method: DrawImageShape() // /// <summary> /// Draws a vertex as a specified image. /// </summary> /// /// <param name="oVertex"> /// The vertex to draw. /// </param> /// /// <param name="oGraphDrawingContext"> /// Provides access to objects needed for graph-drawing operations. /// </param> /// /// <param name="oDrawingContext"> /// The DrawingContext to use. /// </param> /// /// <param name="oDrawingVisual"> /// The <see cref="DrawingVisual" /> object from which <paramref /// name="oDrawingContext" /> was obtained. /// </param> /// /// <param name="eVisibility"> /// The visibility of the vertex. /// </param> /// /// <param name="bDrawAsSelected"> /// true to draw the vertex as selected. /// </param> /// /// <param name="sAnnotation"> /// The annotation to draw next to the image, or null if there is no /// annotation. /// </param> /// /// <param name="oImageSource"> /// The image to draw. /// </param> /// /// <param name="oVertexLabelDrawer"> /// Object that draws a vertex label as an annotation. /// </param> /// /// <returns> /// A VertexDrawingHistory object that retains information about how the /// vertex was drawn. /// </returns> //************************************************************************* protected VertexDrawingHistory DrawImageShape( IVertex oVertex, GraphDrawingContext oGraphDrawingContext, DrawingContext oDrawingContext, DrawingVisual oDrawingVisual, VisibilityKeyValue eVisibility, Boolean bDrawAsSelected, String sAnnotation, ImageSource oImageSource, VertexLabelDrawer oVertexLabelDrawer ) { Debug.Assert(oVertex != null); Debug.Assert(oGraphDrawingContext != null); Debug.Assert(oDrawingContext != null); Debug.Assert(oDrawingVisual != null); Debug.Assert(oImageSource != null); Debug.Assert(oVertexLabelDrawer != null); AssertValid(); // Move the vertex if it falls outside the graph rectangle. Rect oVertexRectangle = GetVertexRectangle( GetVertexLocation(oVertex), oImageSource.Width * m_dGraphScale, oImageSource.Height * m_dGraphScale); MoveVertexIfNecessary(oVertex, ref oVertexRectangle, oGraphDrawingContext); Byte btAlpha = 255; if (!bDrawAsSelected) { // Check for a non-opaque alpha value. btAlpha = GetAlpha(oVertex, eVisibility, btAlpha); } VertexDrawingHistory oVertexDrawingHistory = new ImageVertexDrawingHistory(oVertex, oDrawingVisual, bDrawAsSelected, oVertexRectangle); if (btAlpha > 0) { oDrawingContext.DrawImage(oImageSource, oVertexRectangle); Color oColor = GetColor(oVertex, eVisibility, bDrawAsSelected); // Draw an outline rectangle. oDrawingContext.DrawRectangle(null, GetPen(oColor, DefaultPenThickness), oVertexRectangle); if (btAlpha < 255) { // Real transparency can't be achieved with arbitrary images, // so simulate transparency by drawing on top of the image with // a translucent brush the same color as the graph's // background. // // This really isn't a good solution. Is there are better way // to simulate transparency? Color oTranslucentColor = oGraphDrawingContext.BackColor; oTranslucentColor.A = (Byte)( (Byte)255 - btAlpha ); oDrawingContext.DrawRectangle( CreateFrozenSolidColorBrush(oTranslucentColor), null, oVertexRectangle); } if (sAnnotation != null) { oVertexLabelDrawer.DrawLabel(oDrawingContext, oGraphDrawingContext, oVertexDrawingHistory, oVertexRectangle, CreateFormattedText(sAnnotation, oColor) ); } } return (oVertexDrawingHistory); }
DrawBezierCurve ( IEdge oEdge, GraphDrawingContext oGraphDrawingContext, DrawingContext oDrawingContext, Point oEdgeEndpoint1, Point oEdgeEndpoint2, Boolean bDrawAsSelected, Boolean bDrawArrow, Pen oPen, Color oColor, Double dWidth, VisibilityKeyValue eVisibility, String sLabel ) { Debug.Assert(oEdge != null); Debug.Assert(oGraphDrawingContext != null); Debug.Assert(oDrawingContext != null); Debug.Assert(oPen != null); AssertValid(); Point oBezierControlPoint = GetBezierControlPoint(oGraphDrawingContext, oEdgeEndpoint1, oEdgeEndpoint2, m_dBezierDisplacementFactor); if (bDrawArrow) { // When the edge is a Bezier curve, the arrow should be aligned // along the tangent of the curve at the second endpoint. The // tangent runs from the second endpoint to the Bezier control // point. Double dArrowAngle = WpfGraphicsUtil.GetAngleBetweenPointsRadians( oBezierControlPoint, oEdgeEndpoint2); // Draw the arrow and set the second endpoint to the center of the // flat end of the arrow. Note that in the Bezier case, moving the // second endpoint causes a small distortion of the Bezier curve. oEdgeEndpoint2 = DrawArrow(oDrawingContext, oEdgeEndpoint2, dArrowAngle, oColor, dWidth); } PathGeometry oBezierCurve = WpfPathGeometryUtil.GetQuadraticBezierCurve(oEdgeEndpoint1, oEdgeEndpoint2, oBezierControlPoint); oDrawingContext.DrawGeometry(null, oPen, oBezierCurve); if ( !String.IsNullOrEmpty(sLabel) ) { DrawLabel(oEdge, oDrawingContext, oGraphDrawingContext, bDrawAsSelected, oColor, eVisibility, oEdgeEndpoint1, oEdgeEndpoint2, oBezierCurve, oBezierControlPoint, sLabel); } }
DrawLabelShape ( IVertex oVertex, GraphDrawingContext oGraphDrawingContext, DrawingContext oDrawingContext, DrawingVisualPlus oDrawingVisual, VisibilityKeyValue eVisibility, Boolean bDrawAsSelected, String sLabel, CollapsedGroupDrawingManager oCollapsedGroupDrawingManager ) { Debug.Assert(oVertex != null); Debug.Assert(oGraphDrawingContext != null); Debug.Assert(oDrawingContext != null); Debug.Assert(oDrawingVisual != null); Debug.Assert( !String.IsNullOrEmpty(sLabel) ); Debug.Assert(oCollapsedGroupDrawingManager != null); AssertValid(); // Figure out what colors to use. Color oOutlineColor; Color oTextColor = GetColor(oVertex, eVisibility, false); Color oFillColor = GetColor(oVertex, eVisibility, ReservedMetadataKeys.PerVertexLabelFillColor, m_oLabelFillColor, true); if (bDrawAsSelected) { // The outline color is always the selected color. oOutlineColor = m_oSelectedColor; // The text color is the default or per-vertex color with no alpha. oTextColor.A = 255; // The fill color is the default or per-vertex fill color with no // alpha. oFillColor.A = 255; } else { // The outline color is the default or per-vertex color with alpha. oOutlineColor = oTextColor; // The text color is the default or per-vertex color with alpha. // The fill color is the default or per-vertex fill color with // alpha. } Double dLabelFontSize = GetLabelFontSize(oVertex); FormattedText oFormattedText = CreateFormattedTextWithWrap( sLabel, oTextColor, dLabelFontSize); Rect oVertexRectangle = GetVertexRectangle( GetVertexLocation(oVertex), oFormattedText.Width, oFormattedText.Height); // Pad the text. Rect oVertexRectangleWithPadding = oVertexRectangle; Double dLabelPadding = GetLabelPadding(dLabelFontSize); oVertexRectangleWithPadding.Inflate(dLabelPadding, dLabelPadding * 0.7); if (m_oFormattedTextManager.Typeface.Style != FontStyles.Normal) { // This is a hack to move the right edge of the padded rectangle // to the right to adjust for wider italic text, which // FormattedText.Width does not account for. What is the correct // way to do this? It might involve the FormattedText.Overhang* // properties, but I'll be darned if I can understand how those // properties work. Double dItalicCompensation = dLabelFontSize / 7.0; oVertexRectangleWithPadding.Inflate(dItalicCompensation, 0); oVertexRectangleWithPadding.Offset(dItalicCompensation, 0); } // Move the vertex if it falls outside the graph rectangle. Double dOriginalVertexRectangleWithPaddingX = oVertexRectangleWithPadding.X; Double dOriginalVertexRectangleWithPaddingY = oVertexRectangleWithPadding.Y; MoveVertexIfNecessary(oVertex, oGraphDrawingContext, oCollapsedGroupDrawingManager, ref oVertexRectangleWithPadding); oVertexRectangle.Offset( oVertexRectangleWithPadding.X - dOriginalVertexRectangleWithPaddingX, oVertexRectangleWithPadding.Y - dOriginalVertexRectangleWithPaddingY ); oDrawingVisual.SetEffect( GetRectangleEffect( oGraphDrawingContext, oOutlineColor) ); // Draw the padded rectangle, then the text. WpfGraphicsUtil.DrawPixelAlignedRectangle(oDrawingContext, GetBrush(oFillColor), GetPen(oOutlineColor, DefaultPenThickness), oVertexRectangleWithPadding); oDrawingContext.DrawText(oFormattedText, oVertexRectangle.Location); // Return information about how the vertex was drawn. return ( new LabelVertexDrawingHistory(oVertex, oDrawingVisual, bDrawAsSelected, oVertexRectangleWithPadding) ); }