private void DrawPseudostate(TNode state, D2dGraphics g, bool outline) { RectangleF bounds = state.Bounds; D2dEllipse ellipse = (D2dEllipse)bounds; D2dEllipse innerEllipse = ellipse; innerEllipse.RadiusX = 4; innerEllipse.RadiusY = 4; PointF c = ellipse.Center; g.FillEllipse(ellipse, m_theme.FillBrush); switch (state.Type) { case StateType.Start: g.FillEllipse(innerEllipse, m_theme.TextBrush); break; case StateType.Final: g.DrawEllipse(ellipse, m_theme.OutlineBrush, 3.0f); g.FillEllipse(innerEllipse, m_theme.TextBrush); break; case StateType.ShallowHistory: g.DrawText("H", m_centerText, bounds, m_theme.TextBrush); break; case StateType.DeepHistory: g.DrawText("H*", m_centerText, bounds, m_theme.TextBrush); break; case StateType.Conditional: g.DrawText("C", m_centerText, bounds, m_theme.TextBrush); break; } if (outline && state.Type != StateType.Final) { g.DrawEllipse(ellipse, m_theme.OutlineBrush); } }
/// <summary> /// Draws a partially defined graph edge</summary> /// <param name="fromNode">Source node, or null</param> /// <param name="fromRoute">Source route, or null</param> /// <param name="toNode">Destination node, or null</param> /// <param name="toRoute">Destination route, or null</param> /// <param name="label">Edge label</param> /// <param name="endPoint">Endpoint to substitute for source or destination, if either is null</param> /// <param name="g">Graphics object</param> public override void Draw( TNode fromNode, BoundaryRoute fromRoute, TNode toNode, BoundaryRoute toRoute, string label, Point endPoint, D2dGraphics g) { // put endpoint into statechart space var inverse = g.Transform; inverse.Invert(); PointF end = Matrix3x2F.TransformPoint(inverse, endPoint); PointF p1; PointF normal1; if (fromNode != null) { p1 = ParameterToPoint(fromNode.Bounds, fromRoute.Position, out normal1); } else { p1 = end; normal1 = new Point(); } PointF p4; PointF normal2; if (toNode != null) { p4 = ParameterToPoint(toNode.Bounds, toRoute.Position, out normal2); } else { p4 = end; normal2 = new Point(); } PointF p2, p3; float d = GetTransitionPoints(p1, normal1, p4, normal2, out p2, out p3); DrawEdgeSpline(p1, p2, p3, p4, d, m_theme.OutlineBrush, g); if (!string.IsNullOrEmpty(label)) { BezierCurve2F curve = new BezierCurve2F(p1, p2, p3, p4); Vec2F midpoint = curve.Evaluate(0.5f); g.DrawText(label, m_centerText, new PointF(midpoint.X, midpoint.Y), m_theme.TextBrush); } }
private void Draw(TNode node, D2dGraphics g) { RectangleF boundRect = node.Bounds; D2dEllipse bounds = (D2dEllipse)boundRect; D2dLinearGradientBrush brush = m_theme.FillGradientBrush; brush.StartPoint = boundRect.Location; brush.EndPoint = new PointF(boundRect.Right, boundRect.Bottom); g.FillEllipse(bounds, brush); g.DrawEllipse(bounds, m_theme.OutlineBrush); g.DrawText(node.TitleText, m_theme.TextFormat, boundRect, m_theme.TextBrush); }
private void Draw(TEdge edge, D2dBrush brush, D2dGraphics g) { PointF p1, p2, p3, p4; float d = GetTransitionPoints(edge, out p1, out p2, out p3, out p4); DrawEdgeSpline(p1, p2, p3, p4, d, brush, g); GdiUtil.MakeRectangle(p1, p2); BezierCurve2F curve = new BezierCurve2F(p1, p2, p3, p4); Vec2F midpoint = curve.Evaluate(0.5f); midpoint.X += 2; string label = edge.Label; if (!string.IsNullOrEmpty(label)) { g.DrawText(edge.Label, m_theme.TextFormat, new PointF(midpoint.X, midpoint.Y), m_theme.TextBrush); } }
/// <summary> /// Draws a partially defined graph edge</summary> /// <param name="fromNode">Source node, or null</param> /// <param name="fromRoute">Source route, or null</param> /// <param name="toNode">Destination node, or null</param> /// <param name="toRoute">Destination route, or null</param> /// <param name="label">Edge label</param> /// <param name="endPoint">Endpoint to substitute for source or destination (in client coords), if either is null</param> /// <param name="g">Graphics object</param> public override void Draw( TNode fromNode, NumberedRoute fromRoute, TNode toNode, NumberedRoute toRoute, string label, Point endPoint, D2dGraphics g) { var inverse = g.Transform; inverse.Invert(); PointF end = Matrix3x2F.TransformPoint(inverse, endPoint); TNode node = (fromNode != null) ? fromNode : toNode; CircleF boundary = GetBoundary(node); Vec2F proj = new Vec2F(); if (CircleF.Project(new Vec2F(end), boundary, ref proj)) { PointF start = new PointF(proj.X, proj.Y); g.DrawLine(start, end, m_theme.OutlineBrush); if (fromNode == null) { PointF temp = end; end = start; start = temp; } Vec2F endTangent = new Vec2F(end.X - start.X, end.Y - start.Y); Vec2F arrowPosition = new Vec2F(end); DrawArrow(arrowPosition, endTangent, m_theme.OutlineBrush, g); if (!string.IsNullOrEmpty(label)) { PointF textPoint = new PointF((end.X + start.X) * 0.5f, (end.Y + start.Y) * 0.5f); RectangleF textBox = new RectangleF(textPoint.X - 512, textPoint.Y, 1024, m_theme.TextFormat.FontHeight); //g.DrawString(label, m_theme.Font, m_theme.TextBrush, textBox, m_theme.CenterStringFormat); g.DrawText(label, m_theme.TextFormat, textBox, m_theme.TextBrush); } } }
/// <summary> /// Draws the scrubber manipulator and calculates the bounding rectangle on the handle</summary> /// <param name="g">The graphics object to draw with</param> /// <param name="handleRect">The handle's bounding rectangle for pick tests, in view /// coordinates</param> protected virtual void DrawManipulator(D2dGraphics g, out RectangleF handleRect) { Matrix worldToView = Owner.Transform; float viewX = Sce.Atf.GdiUtil.Transform(worldToView, Position); Rectangle clipRectangle = Owner.VisibleClientRectangle; // allow only the arrow portion to be selected handleRect = new RectangleF( viewX - 5, clipRectangle.Top, 10, 7); g.DrawLine(viewX, clipRectangle.Top, viewX, clipRectangle.Bottom, s_color, 1.0f, null); Color handle_color = m_isMoving ? Color.Tomato : s_color; float pos_x = viewX; float pos_y = clipRectangle.Top + 5; s_arrow[0] = new PointF(pos_x - 4, pos_y - 5); s_arrow[1] = new PointF(pos_x - 4, pos_y); s_arrow[2] = new PointF(pos_x - 5, pos_y + 1); s_arrow[3] = new PointF(pos_x - 5, pos_y + 2); s_arrow[4] = new PointF(pos_x, pos_y + 7); s_arrow[5] = new PointF(pos_x + 5, pos_y + 2); s_arrow[6] = new PointF(pos_x + 5, pos_y + 1); s_arrow[7] = new PointF(pos_x + 4, pos_y); s_arrow[8] = new PointF(pos_x + 4, pos_y - 5); //g.FillPolygon(s_arrow, handle_color); // Fill arrow // Draw arrow border with same gray Photoshop uses //g.DrawLines(s_arrow, Color.FromArgb(116, 114, 106), 3.0f); g.DrawLines(s_arrow, handle_color, 2.0f); string label = Position.ToString(CultureInfo.CurrentCulture); g.DrawText(label, Owner.Renderer.TextFormat, new PointF(pos_x + 6, clipRectangle.Top), SystemColors.WindowText); }
/// <summary> /// Draws floating group pin</summary> /// <param name="grpPin">Group pin</param> /// <param name="inputSide">True for input pin, false for output pin</param> /// <param name="style">DiagramDrawingStyle</param> /// <param name="g">Graphics object</param> public void DrawFloatingGroupPin(ICircuitGroupPin <TElement> grpPin, bool inputSide, DiagramDrawingStyle style, D2dGraphics g) { SizeF pinNameSize = g.MeasureText(grpPin.Name, Theme.TextFormat); PointF p; if (inputSide) { p = GetGroupPinLocation(grpPin, true); RectangleF pinRect = new RectangleF(p.X + CircuitGroupPinInfo.FloatingPinBoxWidth - Theme.PinSize, grpPin.Bounds.Location.Y + Theme.PinMargin + Theme.PinOffset, Theme.PinSize, Theme.PinSize); // draw output pin for input floating pins g.DrawRectangle(pinRect, m_subGraphPinPen); if (grpPin.Info.Pinned) { D2dUtil.DrawPin((int)(p.X + CircuitGroupPinInfo.FloatingPinBoxWidth), (int)p.Y, true, true, m_pinBrush, g); } else { D2dUtil.DrawPin((int)(p.X + CircuitGroupPinInfo.FloatingPinBoxWidth), (int)p.Y + Theme.PinSize / 2, false, true, m_pinBrush, g); } RectangleF bounds = new RectangleF(p.X, p.Y, CircuitGroupPinInfo.FloatingPinBoxWidth, CircuitGroupPinInfo.FloatingPinBoxHeight); RectangleF alignRect = new RectangleF( bounds.Left, bounds.Bottom + Theme.PinMargin, pinNameSize.Width, Theme.RowSpacing); var textAlignment = Theme.TextFormat.TextAlignment; Theme.TextFormat.TextAlignment = D2dTextAlignment.Leading; g.DrawText(grpPin.Name, Theme.TextFormat, alignRect.Location, Theme.TextBrush); Theme.TextFormat.TextAlignment = textAlignment; } else { // assume vertical scroll bar width = 16 p = GetGroupPinLocation(grpPin, false); RectangleF pinRect = new RectangleF(p.X + 1, grpPin.Bounds.Location.Y + Theme.PinMargin + Theme.PinOffset, Theme.PinSize, Theme.PinSize); // draw input pin for output floating pins g.DrawRectangle(pinRect, m_subGraphPinPen); // draw pin icon if (grpPin.Info.Pinned) { D2dUtil.DrawPin((int)p.X, (int)p.Y, true, false, m_pinBrush, g); } else { D2dUtil.DrawPin((int)p.X, (int)p.Y + Theme.PinSize / 2, false, false, m_pinBrush, g); } // draw label RectangleF bounds = new RectangleF(p.X, p.Y, CircuitGroupPinInfo.FloatingPinBoxWidth, CircuitGroupPinInfo.FloatingPinBoxHeight); RectangleF alignRectF = new RectangleF(bounds.Right - pinNameSize.Width, bounds.Bottom + Theme.PinMargin, pinNameSize.Width, Theme.RowSpacing); var textAlignment = Theme.TextFormat.TextAlignment; Theme.TextFormat.TextAlignment = D2dTextAlignment.Trailing; g.DrawText(grpPin.Name, Theme.TextFormat, alignRectF, Theme.TextBrush); Theme.TextFormat.TextAlignment = textAlignment; } // draw the fake pin node itself float savedStrokeWidth = Theme.StrokeWidth; Theme.StrokeWidth = 2.0f; if (style == DiagramDrawingStyle.Normal) { g.DrawRectangle(new RectangleF(p.X, p.Y, CircuitGroupPinInfo.FloatingPinBoxWidth, CircuitGroupPinInfo.FloatingPinBoxHeight), m_subGraphPinNodePen); } else { g.DrawRectangle(new RectangleF(p.X, p.Y, CircuitGroupPinInfo.FloatingPinBoxWidth, CircuitGroupPinInfo.FloatingPinBoxHeight), Theme.HotBrush); } Theme.StrokeWidth = savedStrokeWidth; if (!grpPin.Info.ExternalConnected) { RectangleF eyeRect = GetVisibilityCheckRect(grpPin, inputSide); g.DrawEyeIcon(eyeRect, grpPin.Info.Visible ? m_visiblePinBrush : m_hiddrenPinBrush, 1.0f); } // draw fake edge that connects group pin fake node DrawGroupPinNodeFakeEdge(grpPin, p, inputSide, style, g); }
private void Draw(TEdge edge, D2dBrush brush, D2dGraphics g) { Vec2F startPoint = new Vec2F(); Vec2F endPoint = new Vec2F(); CircleF c = new CircleF(); bool moreThan180 = false; Vec2F endTangent; Vec2F textPoint; int route = edge.FromRoute.Index; if (GetEdgeGeometry(edge, route, ref startPoint, ref endPoint, ref c, ref moreThan180)) { g.DrawLine(new PointF(startPoint.X, startPoint.Y), new PointF(endPoint.X, endPoint.Y), brush, m_theme.StrokeWidth); endTangent = endPoint - startPoint; textPoint = (endPoint + startPoint) * 0.5f; } else { // prepare to draw arc RectangleF rect = new RectangleF(c.Center.X - c.Radius, c.Center.Y - c.Radius, 2 * c.Radius, 2 * c.Radius); double angle1 = Math.Atan2(startPoint.Y - c.Center.Y, startPoint.X - c.Center.X); double angle2 = Math.Atan2(endPoint.Y - c.Center.Y, endPoint.X - c.Center.X); const double twoPi = 2 * Math.PI; // swap so we always go clockwise if (angle1 > angle2) { double temp = angle1; angle1 = angle2; angle2 = temp; } double startAngle = angle1; double sweepAngle = angle2 - angle1; if (moreThan180) { if (sweepAngle < Math.PI) { sweepAngle = -(twoPi - sweepAngle); } } else { if (sweepAngle > Math.PI) { sweepAngle = -(twoPi - sweepAngle); } } const double RadiansToDegrees = 360 / twoPi; startAngle *= RadiansToDegrees; sweepAngle *= RadiansToDegrees; g.DrawArc((D2dEllipse)rect, brush, (float)startAngle, (float)sweepAngle, m_theme.StrokeWidth); endTangent = endPoint - c.Center; endTangent = endTangent.Perp; textPoint = (endPoint + startPoint) * 0.5f; CircleF.Project(textPoint, c, ref textPoint); if (moreThan180) { textPoint -= 2 * (textPoint - c.Center); } } DrawArrow(endPoint, endTangent, brush, g); string label = edge.Label; if (!string.IsNullOrEmpty(label)) { RectangleF textBox = new RectangleF(textPoint.X - 512, textPoint.Y, 1024, m_theme.TextFormat.FontHeight); g.DrawText(label, m_theme.TextFormat, textBox, m_theme.TextBrush); } }
/// <summary> /// Draws a horizontal chart scale</summary> /// <param name="g">The Direct2D graphics object</param> /// <param name="transform">Graph (world) to window's client (screen) transform</param> /// <param name="graphRect">Graph rectangle</param> /// <param name="top">Whether or not the scale should be aligned along the top of the rectangle</param> /// <param name="majorSpacing">Spacing, in pixels, between major tick marks</param> /// <param name="minimumGraphStep">Minimum spacing, in graph (world) space, between ticks. /// For example, 1.0 would limit ticks to being drawn on whole integers.</param> /// <param name="lineBrush">Scale line pen</param> /// <param name="textFormat">Text format</param> /// <param name="textBrush">Text brush</param> public static void DrawHorizontalScale( this D2dGraphics g, Matrix transform, RectangleF graphRect, bool top, int majorSpacing, float minimumGraphStep, D2dBrush lineBrush, D2dTextFormat textFormat, D2dBrush textBrush) { double xScale = transform.Elements[0]; RectangleF clientRect = Transform(transform, graphRect); double tickEnd, majorTickStart, minorTickStart, textStart; if (top) { tickEnd = clientRect.Top + 1; majorTickStart = tickEnd + 12; minorTickStart = tickEnd + 6; textStart = tickEnd + 8; } else { tickEnd = clientRect.Bottom - 1; majorTickStart = tickEnd - 12; minorTickStart = tickEnd - 6; textStart = tickEnd - 19; } double min = Math.Min(graphRect.Left, graphRect.Right); double max = Math.Max(graphRect.Left, graphRect.Right); double tickAnchor = CalculateTickAnchor(min, max); double majorGraphStep = CalculateStep( min, max, Math.Abs(clientRect.Right - clientRect.Left), majorSpacing, minimumGraphStep); int numMinorTicks = CalculateNumMinorTicks(majorGraphStep, minimumGraphStep, 5); double cMinorStep = (majorGraphStep / numMinorTicks) * xScale; if (majorGraphStep > 0) { double offset = tickAnchor - min; offset = offset - MathUtil.Remainder(offset, majorGraphStep); // draw leading minor ticks double cmx; cmx = ((tickAnchor - (offset + majorGraphStep)) - min) * xScale + clientRect.Left + cMinorStep; for (int i = 0; i < numMinorTicks - 1 && cmx < clientRect.Right; i++) { // cull minor ticks outside of the view if (cmx > clientRect.Left) { g.DrawLine((float)cmx, (float)minorTickStart, (float)cmx, (float)tickEnd, lineBrush); } cmx += cMinorStep; } for (double x = tickAnchor - offset; x < max; x += majorGraphStep) { double cx = (x - min) * xScale + clientRect.Left; g.DrawLine((float)cx, (float)majorTickStart, (float)cx, (float)tickEnd, lineBrush); string xString = String.Format("{0:G8}", Math.Round(x, 6)); SizeF textSize = g.MeasureText(xString, textFormat); var textRect = new RectangleF(new PointF((float)cx + 1, (float)textStart), textSize); g.DrawText(xString, textFormat, textRect, textBrush); // draw minor ticks cmx = cx + cMinorStep; for (int i = 0; i < numMinorTicks - 1 && cmx < clientRect.Right; i++) { g.DrawLine((float)cmx, (float)minorTickStart, (float)cmx, (float)tickEnd, lineBrush); cmx += cMinorStep; } } } }
private void Draw(TNode state, D2dGraphics g, bool outline) { RectangleF bounds = state.Bounds; if (state.Type != StateType.Normal) { DrawPseudostate(state, g, outline); } else { float scaleX = g.Transform.M11; // assume no rotation. float radInPixel = scaleX * CornerRadius; IComplexState <TNode, TEdge> complexState = state as IComplexState <TNode, TEdge>; StateIndicators indicators = state.Indicators; if ((indicators & StateIndicators.Active) != 0) { if (radInPixel > MinRadiusInPixel) { D2dEllipse ellipse = new D2dEllipse(); ellipse.RadiusX = CornerRadius; ellipse.RadiusY = CornerRadius; ellipse.Center = bounds.Location; g.FillEllipse(ellipse, Color.SpringGreen); } } if (radInPixel > MinRadiusInPixel) { m_stateRect.Rect = bounds; D2dLinearGradientBrush gradbrush = m_theme.FillGradientBrush; gradbrush.StartPoint = bounds.Location; gradbrush.EndPoint = new PointF(bounds.Right, bounds.Bottom); g.FillRoundedRectangle(m_stateRect, gradbrush); if (outline) { g.DrawRoundedRectangle(m_stateRect, m_theme.OutlineBrush); } } else { g.FillRectangle(bounds, m_theme.FillBrush); if (outline) { g.DrawRectangle(bounds, m_theme.OutlineBrush); } } g.DrawLine(bounds.Left, bounds.Top + m_fontHeight + Margin, bounds.Right, bounds.Top + m_fontHeight + Margin, m_theme.OutlineBrush); if ((scaleX * m_fontHeight) > MinFontHeightInPixel) { g.DrawText(complexState.TitleText, m_theme.TextFormat, new PointF(bounds.X + CornerRadius, bounds.Y + Margin), m_theme.TextBrush); } //RectangleF textBounds = new RectangleF( // (float)(bounds.Left + 4), // (float)(bounds.Top + m_fontHeight + 2), // (float)(bounds.Width - 5), // (float)(bounds.Height - m_fontHeight - 4)); //g.DrawString(complexState.Text, m_theme.Font, m_theme.TextBrush, textBounds, s_stateTextFormat); //IList<int> partitionWidths = complexState.PartitionSizes; //if (partitionWidths.Count > 0) //{ // // draw AND-state dividers // int lastDivider = bounds.Left; // foreach (int width in partitionWidths) // { // g.DrawLine( // m_dividerPen, // lastDivider, bounds.Y + m_fontHeight + Margin, // lastDivider, bounds.Y + bounds.Height); // lastDivider += width; // } //} } }