private Rectangle GetLabelBounds(TEdge edge, D2dGraphics g) { Vec2F startPoint = new Vec2F(); Vec2F endPoint = new Vec2F(); CircleF c = new CircleF(); bool moreThan180 = false; Vec2F textPoint; if (GetEdgeGeometry(edge, edge.FromRoute.Index, ref startPoint, ref endPoint, ref c, ref moreThan180)) { textPoint = (endPoint + startPoint) * 0.5f; } else { textPoint = (endPoint + startPoint) * 0.5f; CircleF.Project(textPoint, c, ref textPoint); if (moreThan180) { textPoint -= 2 * (textPoint - c.Center); } } float height = m_theme.TextFormat.FontHeight; float width = 32; if (!string.IsNullOrEmpty(edge.Label)) { SizeF size = g.MeasureText(edge.Label, m_theme.TextFormat); width = size.Width; height = size.Height; } return(new Rectangle((int)(textPoint.X - width * 0.5f), (int)textPoint.Y, (int)width, (int)height)); }
/// <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); }
/// <summary> /// Finds node and/or edge hit by the given point</summary> /// <param name="graph">Graph to test</param> /// <param name="priorityEdge">Graph edge to test before others</param> /// <param name="p">Point to test</param> /// <param name="g">Graphics object</param> /// <returns>Hit record containing node and/or edge hit by the given point</returns> public override GraphHitRecord <TElement, TWire, TPin> Pick( IGraph <TElement, TWire, TPin> graph, TWire priorityEdge, PointF p, D2dGraphics g) { var hitRecord = base.Pick(graph, priorityEdge, p, g); if (hitRecord.Node != null || hitRecord.Edge != null || hitRecord.Part != null) { return(hitRecord); } // check whether hits virtual parts of group pin var group = graph.Cast <ICircuitGroupType <TElement, TWire, TPin> >(); foreach (var pin in group.Inputs.Concat(group.Info.HiddenInputPins)) { var grpPin = pin.Cast <ICircuitGroupPin <TElement> >(); // check whether hit the thumbtack of a floating pin var pinRect = GetThumbtackRect(grpPin, true); if (pinRect.Contains(p)) { var pinPart = new DiagramPin(pinRect); return(new GraphHitRecord <TElement, TWire, TPin>((TPin)grpPin, pinPart)); } // check whether hit the visibility check(eye icon) var eyeRect = GetVisibilityCheckRect(grpPin, true); if (eyeRect.Contains(p)) { var eyePart = new DiagramVisibilityCheck(eyeRect); return(new GraphHitRecord <TElement, TWire, TPin>((TPin)grpPin, eyePart)); } // check whether hit the floating pin label-part PointF grpPos = GetGroupPinLocation(grpPin, true); RectangleF bounds = new RectangleF(grpPos.X, grpPos.Y, CircuitGroupPinInfo.FloatingPinBoxWidth, CircuitGroupPinInfo.FloatingPinBoxHeight); SizeF nameSize = g.MeasureText(grpPin.Name, Theme.TextFormat); RectangleF labelBounds = new RectangleF(bounds.Left, bounds.Bottom + Theme.PinMargin, (int)nameSize.Width, Theme.RowSpacing); //labelBounds = GdiUtil.Transform(g.Transform, labelBounds); var labelPart = new DiagramLabel( new Rectangle((int)labelBounds.Left, (int)labelBounds.Top, (int)labelBounds.Width, (int)labelBounds.Height), TextFormatFlags.SingleLine | TextFormatFlags.Left); if (labelBounds.Contains(p)) { return(new GraphHitRecord <TElement, TWire, TPin>((TPin)grpPin, labelPart)); } // check whether hit the floating pin node if (bounds.Contains(p)) { var result = new GraphHitRecord <TElement, TWire, TPin>((TPin)grpPin, null); result.DefaultPart = labelPart; return(result); } } foreach (var pin in group.Outputs.Concat(group.Info.HiddenOutputPins)) { var grpPin = pin.Cast <ICircuitGroupPin <TElement> >(); // check whether hit the thumbtack of a floating pin var pinRect = GetThumbtackRect(grpPin, false); if (pinRect.Contains(p)) { var pinPart = new DiagramPin(pinRect); return(new GraphHitRecord <TElement, TWire, TPin>((TPin)grpPin, pinPart)); } // check whether hit the visibility check(eye icon) var eyeRect = GetVisibilityCheckRect(grpPin, false); if (eyeRect.Contains(p)) { var eyePart = new DiagramVisibilityCheck(eyeRect); return(new GraphHitRecord <TElement, TWire, TPin>((TPin)grpPin, eyePart)); } // check whether hit the floating pin label-part PointF grpPos = GetGroupPinLocation(grpPin, false); RectangleF bounds = new RectangleF(grpPos.X, grpPos.Y, CircuitGroupPinInfo.FloatingPinBoxWidth, CircuitGroupPinInfo.FloatingPinBoxHeight); SizeF nameSize = g.MeasureText(grpPin.Name, Theme.TextFormat); RectangleF labelBounds = new RectangleF(bounds.Right - (int)nameSize.Width, bounds.Bottom + Theme.PinMargin, (int)nameSize.Width, Theme.RowSpacing); //labelBounds = GdiUtil.Transform(g.Transform, labelBounds); var labelPart = new DiagramLabel( new Rectangle((int)labelBounds.Left, (int)labelBounds.Top, (int)labelBounds.Width, (int)labelBounds.Height), TextFormatFlags.SingleLine | TextFormatFlags.Right); if (labelBounds.Contains(p)) { return(new GraphHitRecord <TElement, TWire, TPin>((TPin)grpPin, labelPart)); } // check whether hit the floating pin node if (bounds.Contains(p)) { var result = new GraphHitRecord <TElement, TWire, TPin>((TPin)grpPin, null); result.DefaultPart = labelPart; return(result); } } return(hitRecord); }
/// <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 Rectangle GetLabelBounds(TEdge edge, D2dGraphics g) { Vec2F startPoint = new Vec2F(); Vec2F endPoint = new Vec2F(); CircleF c = new CircleF(); bool moreThan180 = false; Vec2F textPoint; int route = edge.FromRoute.Index; if (GetEdgeGeometry(edge, route, ref startPoint, ref endPoint, ref c, ref moreThan180)) { 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; textPoint = (endPoint + startPoint) * 0.5f; CircleF.Project(textPoint, c, ref textPoint); if (moreThan180) { textPoint -= 2 * (textPoint - c.Center); } } float height = m_theme.TextFormat.FontHeight; float width = 32; if (!string.IsNullOrEmpty(edge.Label)) { SizeF size = g.MeasureText(edge.Label, m_theme.TextFormat); width = size.Width; height = size.Height; } return(new Rectangle((int)(textPoint.X - width * 0.5f), (int)textPoint.Y, (int)width, (int)height)); }