using System; using System.Drawing; using System.Drawing.Drawing2D; namespace DevComponents.AdvTree { namespace Display { /// /// Base class for drawing node connectors. /// public abstract class NodeConnectorDisplay { //private bool m_RootNode=false; //private bool m_DrawRootAllLevels=false; //private bool m_EndCap=true; //private bool m_DrawConnectorUnderNodes=true; /// /// Creates new instance of the object. /// public NodeConnectorDisplay() { } /// /// Draws connector line between two nodes. /// /// Connector context information. public virtual void DrawConnector(ConnectorRendererEventArgs info){} ///// ///// Returns the connector starting coordinates. ///// ///// Connector display information. ///// Point object. //protected virtual Point GetStartPoint(ConnectorRendererEventArgs info) //{ // Point p=Point.Empty; // if(info.IsRootNode) // { // //int toMidPoint=info.ToNode.Bounds.Top+info.ToNode.Bounds.Height/2; // //if(info.FromNode.Bounds.Top>toMidPoint) // if(IsAbove(info.FromNode,info.ToNode)) // p=new Point(info.FromNode.BoundsRelative.Left+info.FromNode.BoundsRelative.Width/2,info.FromNode.BoundsRelative.Top); // //else if(info.FromNode.Bounds.Bottom ///// Returns true if fromNode is above the toNode. ///// ///// From Node object. ///// To Node object ///// True if fromNode is above toNode. //protected bool IsAbove(Node fromNode, Node toNode) //{ // //int toMidPoint=toNode.Bounds.Top+toNode.Bounds.Height/2; // //if(fromNode.Bounds.Top>toMidPoint) // if(fromNode.BoundsRelative.Top>toNode.BoundsRelative.Bottom) // return true; // return false; //} ///// ///// Returns true if fromNode is below toNode. ///// ///// From Node object. ///// To Node object. ///// True if fromNode is below toNode. //protected bool IsBelow(Node fromNode, Node toNode) //{ // int toMidPoint=toNode.BoundsRelative.Top+toNode.BoundsRelative.Height/2; // if(fromNode.BoundsRelative.Bottom ///// Returns whether connector is extended to underline the node. ///// ///// Refernce to Node style. ///// True if node should be underlined by connector. //protected bool UnderlineNode(ElementStyle nodeStyle) //{ // if(!nodeStyle.PaintBottomBorder && !nodeStyle.PaintTopBorder && // !nodeStyle.PaintLeftBorder && !nodeStyle.PaintRightBorder) // return true; // return false; //} ///// ///// Returns the connector end point. The array of end points. Two valid points will be returned if node needs to be underlined by connector. ///// ///// Connector display info. ///// Array of point objects. //protected Point[] GetEndPoint(ConnectorRendererEventArgs info) //{ // // If to element is to the right of the from node and has left border end point is the vertical mid-point // // If to element is to the left of the from node and has right border end point is the vertical mid-point // // If there is no border end point is text bottom // // If this is link connector the end point is the middle bottom or top point of the node // Point p=Point.Empty; // Point pLineEnd=Point.Empty; // int capWidthOffset = 0; // GetCapWidthOffset(info.NodeConnector.EndCap, info.NodeConnector.EndCapSize); // bool leftSide=this.IsOnLeftSide(info.FromNode,info.ToNode); // if(info.LinkConnector && info.FromNode.BoundsRelative.Top>info.ToNode.BoundsRelative.Bottom) // p=new Point(info.ToNode.BoundsRelative.X+info.ToNode.BoundsRelative.Width/2+(leftSide?capWidthOffset:-capWidthOffset),info.ToNode.BoundsRelative.Bottom+1); // else if(info.LinkConnector && info.FromNode.BoundsRelative.Bottom ///// Returns the offest for the node connector cap. ///// ///// Cap type. ///// Cap size. ///// //protected int GetCapWidthOffset(eConnectorCap cap,Size size) //{ // int capWidthOffset=0; // switch(cap) // { // case eConnectorCap.Arrow: // capWidthOffset=size.Width+1; // break; // case eConnectorCap.Ellipse: // capWidthOffset=size.Width; // break; // } // return capWidthOffset; //} ///// ///// Returns true if source node is on the left side of the target node. ///// ///// Reference to source node. ///// Reference to target node. ///// True if source is on the left side of target. //protected bool IsOnLeftSide(Node source, Node target) //{ // if((source.BoundsRelative.Left+source.BoundsRelative.Width/2)>target.BoundsRelative.Left) // return true; // return false; //} /// /// Returns new instance of pen object for node connector line. Caller is responsible for /// disposing of this object. /// /// Node connector display info. /// New instance of Pen object. protected Pen GetLinePen(ConnectorRendererEventArgs info) { Pen pen = new Pen(info.NodeConnector.LineColor, info.NodeConnector.LineWidth); pen.DashStyle = info.NodeConnector.DashStyle; return pen; } ///// ///// Returns new instance of pen object for the end node connector line. Caller is responsible for ///// disposing of this object. ///// ///// Node connector display info. ///// New instance of Pen object. //protected Pen GetEndLinePen(ConnectorRendererEventArgs info) //{ // return new Pen(info.NodeConnector.LineColor,EndLineWidth); //} ///// ///// Returns new instance of pen object for the node underline line. Caller is responsible for ///// disposing of this object. ///// ///// Node connector display info. ///// New instance of Pen object. //protected Pen GetEndUnderlinePen(ConnectorRendererEventArgs info) //{ // return new Pen(info.NodeConnector.LineColor,EndLineWidth); //} //private int EndLineWidth //{ // get {return 1;} //} // /// // /// Draws straight line connector between start and end point. // /// // /// Node connector display info. // /// Start point. // /// End point. // /// Underline end point if any. // protected void DrawStraightLineConnector(ConnectorRendererEventArgs info, Point pStart, Point pEnd) // { // using (Pen pen = this.GetLinePen(info)) // { // if (pen.DashStyle != DashStyle.Solid) // { // SmoothingMode sm = info.Graphics.SmoothingMode; // info.Graphics.SmoothingMode = SmoothingMode.Default; // info.Graphics.DrawLine(pen, pStart, pEnd); // info.Graphics.SmoothingMode = sm; // } // else // info.Graphics.DrawLine(pen, pStart, pEnd); // } // } // /// // /// Draws straight line connector between start and end point. // /// // /// Node connector display info. // /// Start point. // /// End point. // /// Underline end point if any. // protected void DrawLineConnector(ConnectorRendererEventArgs info,Point pStart,Point pEnd, Point pEndUnderLine) // { // if(info.NodeConnector.LineWidth>1) // { // // Merge lines nicely by filling and creating path... // int rootLineWidth=this.EndLineWidth; // int lineWidth=info.NodeConnector.LineWidth; // using(Brush brush=GetLineBrush(info)) // { // GraphicsPath path=GetConnectingPath(pStart,pEnd,lineWidth,rootLineWidth,info.IsRootNode,!(IsAbove(info.FromNode,info.ToNode) || IsBelow(info.FromNode,info.ToNode))); // info.Graphics.FillPath(brush,path); // } // } // else // { // using(Pen pen=this.GetLinePen(info)) // { // info.Graphics.DrawLine(pen,pStart,pEnd); // } // } // if(!pEndUnderLine.IsEmpty) // { // using(Pen pen=this.GetEndUnderlinePen(info)) // { // info.Graphics.DrawLine(pen,pEnd,pEndUnderLine); // } // } // } // private GraphicsPath GetConnectingPath(Point pStart, Point pEnd, int lineStartWidth, int lineEndWidth, bool bRoot, bool bRootSide) // { // int direction=1; // if(pStart.X>pEnd.X) // direction=-1; // lineStartWidth++; // lineEndWidth++; // GraphicsPath path=new GraphicsPath(); // if(bRoot && !bRootSide) // { // path.AddLine(pStart.X,pStart.Y,pStart.X+lineStartWidth*direction,pStart.Y); //// if(direction>0) //// path.AddLine(pEnd.X+lineEndWidth*direction,pEnd.Y,pEnd.X,pEnd.Y); //// else //// path.AddLine(pEnd.X,pEnd.Y,pEnd.X+lineEndWidth*direction,pEnd.Y); // if(direction>0) // { // path.AddLine(pStart.X+lineStartWidth*direction,pStart.Y, pEnd.X, pEnd.Y); // path.AddLine(pEnd.X, pEnd.Y, pEnd.X, pEnd.Y + lineEndWidth*direction); // path.AddLine(pEnd.X, pEnd.Y + lineEndWidth*direction, pStart.X, pStart.Y); // } // else // path.AddLine(pEnd.X, pEnd.Y, pEnd.X, pEnd.Y + lineEndWidth*direction); // path.CloseAllFigures(); //// if(Math.Abs(pEnd.Y-pStart.Y)<=8) //// path.Widen(SystemPens.Highlight); // } // else // { // int offsetStart=lineStartWidth/2; // int offsetEnd=lineEndWidth/2; // path.AddLine(pStart.X,pStart.Y-offsetStart,pStart.X,pStart.Y+offsetStart); // path.AddLine(pEnd.X,pEnd.Y+offsetEnd,pEnd.X,pEnd.Y-offsetEnd); // path.AddLine(pEnd.X,pEnd.Y-offsetEnd,pStart.X,pStart.Y-offsetStart); // path.CloseAllFigures(); // } // return path; // } // protected Brush GetLineBrush(ConnectorRendererEventArgs info) // { // return new SolidBrush(info.NodeConnector.LineColor); // } // protected void DrawEndLine(ConnectorRendererEventArgs info,Point pStart,Point pEnd,Point pEndUnderLine) // { // if(pEndUnderLine.IsEmpty) // { // switch(info.NodeConnector.EndCap) // { // case eConnectorCap.Ellipse: // { // using(Pen pen=this.GetEndLinePen(info)) // { // Size endCapSize=info.NodeConnector.EndCapSize; // if(pStart.XpEnd.X) // direction=-1; // info.Graphics.DrawLine(pen,pEnd,new Point(pEnd.X+info.NodeConnector.EndCapSize.Width/3*direction,pEnd.Y)); // Size endCapSize=info.NodeConnector.EndCapSize; // GraphicsPath arrow=GetArrowPath(endCapSize,pStart,pEnd); // info.Graphics.DrawPath(pen,arrow); // } // break; // } // } // } // else // { // using(Pen pen=this.GetEndUnderlinePen(info)) // { // info.Graphics.DrawLine(pen,pEnd,pEndUnderLine); // // Connect underline to expand part // if(NodeDisplay.DrawExpandPart(info.ToNode)) // { // Rectangle re=NodeDisplay.GetNodeRectangle(eNodeRectanglePart.ExpandBounds,info.ToNode,info.Offset); // Point p2=new Point((re.X>pEndUnderLine.X?re.X:re.Right)+(re.Width/2*(re.X>pEndUnderLine.X?1:-1)),re.Bottom); // Point p1=new Point(p2.X,pEndUnderLine.Y+(pEndUnderLine.Y>p2.Y?(p2.Y-pEndUnderLine.Y)/2:-(p2.Y-pEndUnderLine.Y)/2)); // info.Graphics.DrawCurve(pen,new Point[]{pEndUnderLine,p1,p2},.5f); // } // } // } // } // private GraphicsPath GetArrowPath(Size capSize,Point pStart,Point pEnd) // { // GraphicsPath path=new GraphicsPath(); // int direction=1; // if(pStart.X>pEnd.X) // direction=-1; // pEnd.X+=(GetCapWidthOffset(eConnectorCap.Arrow,capSize)*direction); // path.AddLine(pEnd.X,pEnd.Y,pEnd.X-capSize.Width*direction,pEnd.Y-capSize.Height/2); // path.AddLine(pEnd.X-(2*capSize.Width/3*direction),pEnd.Y,pEnd.X-capSize.Width*direction,pEnd.Y+capSize.Height/2); // path.CloseAllFigures(); // return path; // } //internal virtual ConnectorPointInfo GetConnectorPointInfo(ConnectorRendererEventArgs info, Point pStart, Point pEnd) //{ // ConnectorPointInfo pointInfo=new ConnectorPointInfo(); // int xMulti=1/*, yMulti=1*/; // int lineWidth=info.NodeConnector.LineWidth; // // used for direction control // if(pStart.X>pEnd.X) // xMulti=-1; // //if(pStart.Y>pEnd.Y) // // yMulti=-1; // if(info.ConnectorPoints!=null) // { // Point connPointsOffset=info.ToNode.BoundsRelative.Location; // connPointsOffset.Offset(info.Offset.X,info.Offset.Y); // GraphicsPath path=new GraphicsPath(); // pointInfo.Points1=new Point[info.ConnectorPoints.Count+2]; // pointInfo.Points1[0]=pStart; // pointInfo.Points1[pointInfo.Points1.Length-1]=pEnd; // if(lineWidth>1) // { // pointInfo.Points2=new Point[info.ConnectorPoints.Count+2]; // pointInfo.Points2[pointInfo.Points2.Length-1]=pStart; // pointInfo.Points2[0]=pEnd; // int i=pointInfo.Points1.Length-2; // int k=1; // foreach(Point pcp in info.ConnectorPoints) // { // pointInfo.Points1[i]=pcp; // pointInfo.Points1[i].Offset(connPointsOffset.X,connPointsOffset.Y); // pointInfo.Points2[k]=new Point(pcp.X+lineWidth*xMulti,pcp.Y); // pointInfo.Points2[k].Offset(connPointsOffset.X,connPointsOffset.Y); // k++; // i--; // } // } // else // { // int i=pointInfo.Points1.Length-2; // foreach(Point pcp in info.ConnectorPoints) // { // pointInfo.Points1[i]=pcp; // pointInfo.Points1[i].Offset(connPointsOffset.X,connPointsOffset.Y); // i--; // } // } // } // return pointInfo; //} } } /// /// Represents custom connector path info. /// internal class ConnectorPointInfo { public Point[] Points1=null; public Point[] Points2=null; } }