/// <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 <TNode, TEdge, BoundaryRoute> Pick( IGraph <TNode, TEdge, BoundaryRoute> graph, TEdge priorityEdge, Point p, Graphics g) { int tolerance = m_theme.PickTolerance; TNode pickedNode = null; TEdge pickedEdge = null; BoundaryRoute fromRoute = null; BoundaryRoute toRoute = null; Vec2F v = new Vec2F(p.X, p.Y); if (priorityEdge != null && Pick(priorityEdge, v)) { pickedEdge = priorityEdge; } else { foreach (TEdge edge in graph.Edges.Reverse()) { if (Pick(edge, v)) { pickedEdge = edge; break; } } } foreach (TNode state in graph.Nodes.Reverse()) { Rectangle bounds = state.Bounds; bounds.Inflate(tolerance, tolerance); if (bounds.Contains(p)) { pickedNode = state; float position = PointToParameter(bounds, p); bounds.Inflate(-2 * tolerance, -2 * tolerance); bool onEdge = !bounds.Contains(p); if (pickedEdge == null) { if (onEdge) { // edge of node can be source or destination fromRoute = new BoundaryRoute(position); toRoute = new BoundaryRoute(position); } } else // hit on edge and node { if (onEdge) { if (pickedEdge.FromNode == pickedNode) { fromRoute = new BoundaryRoute(position); } else if (pickedEdge.ToNode == pickedNode) { toRoute = new BoundaryRoute(position); } } } break; } } IComplexState <TNode, TEdge> complexState = pickedNode as IComplexState <TNode, TEdge>; if (complexState != null && pickedEdge == null) { Rectangle bounds = pickedNode.Bounds; Rectangle labelBounds = new Rectangle( bounds.X + CornerRadius, bounds.Y + Margin, bounds.Width - 2 * CornerRadius, m_theme.Font.Height); if (labelBounds.Contains(p)) { DiagramLabel label = new DiagramLabel(labelBounds, TextFormatFlags.SingleLine); return (new GraphHitRecord <TNode, TEdge, BoundaryRoute>(pickedNode, label)); } } return (new GraphHitRecord <TNode, TEdge, BoundaryRoute>(pickedNode, pickedEdge, fromRoute, toRoute)); }
private void Draw(TNode state, Graphics g) { Rectangle bounds = state.Bounds; if (state.Type != StateType.Normal) { DrawPseudostate(bounds.Location, state.Type, m_theme.OutlinePen, g); } else { IComplexState <TNode, TEdge> complexState = state as IComplexState <TNode, TEdge>; // Prevent an exception being thrown by LinearGradientBrush. if (bounds.Width <= 0) { bounds.Width = 1; } if (bounds.Height <= 0) { bounds.Height = 1; } StateIndicators indicators = state.Indicators; if ((indicators & StateIndicators.Active) != 0) { g.FillEllipse( Brushes.SpringGreen, bounds.X - CornerRadius, bounds.Y - CornerRadius, 2 * CornerRadius, 2 * CornerRadius); } // draw state lozenge using (GraphicsPath gp = GetStatePath(bounds)) { if (!IsPrinting) { using (LinearGradientBrush interiorBrush = new LinearGradientBrush( bounds, Color.WhiteSmoke, Color.LightGray, LinearGradientMode.ForwardDiagonal)) { g.FillPath(interiorBrush, gp); } } else { g.FillPath(Brushes.White, gp); } g.DrawPath(m_theme.OutlinePen, gp); } g.DrawString( complexState.Name, m_theme.Font, m_theme.TextBrush, bounds.X + CornerRadius, bounds.Y + Margin); g.DrawLine( m_theme.OutlinePen, bounds.Left, bounds.Top + m_fontHeight + Margin, bounds.Right, bounds.Top + m_fontHeight + Margin); 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; // } //} } }
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; // } //} } }