ConnectorEditor.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / NetFx40 / Tools / System.Activities.Core.Presentation / System / Activities / Core / Presentation / ConnectorEditor.cs / 1305376 / ConnectorEditor.cs

                            //------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------

namespace System.Activities.Core.Presentation 
{
    using System.Collections.Generic; 
    using System.Diagnostics; 
    using System.Windows;
    using System.Windows.Controls; 
    using System.Windows.Documents;
    using System.Windows.Media;
    using System.Windows.Shapes;
    using System.Windows.Input; 
    using System.Runtime;
    using System.Activities.Presentation; 
 
    internal class ConnectorEditor
    { 
        const double EditPointRadius = 4;
        const double EditPointHitTestRadius = 9;
        const int minLengthForSegmentEditPoint = 10;
        EditPoint activeEditPoint; 
        AdornerLayer adornerLayer;
        Connector editedConnector; 
        List editPoints; 
        FreeFormPanel parentPanel;
 
        public ConnectorEditor(FreeFormPanel panel, Connector connector)
        {
            if (panel == null)
            { 
                throw FxTrace.Exception.AsError(new ArgumentNullException("panel"));
            } 
            if (connector == null) 
            {
                throw FxTrace.Exception.AsError(new ArgumentNullException("connector")); 
            }
            this.editPoints = new List();
            this.parentPanel = panel;
            this.editedConnector = connector; 
            this.activeEditPoint = null;
            connector.IsSelected = true; 
            DisplayEditPoints(); 
        }
        public bool BeingEdited 
        {
            get
            {
                return (this.activeEditPoint != null); 
            }
        } 
 
        public bool IsConnectorStartBeingMoved
        { 
            get
            {
                return (this.BeingEdited && this.activeEditPoint.Type == EditPoint.EditPointTypes.ConnectionEditPoint
                    && this.editedConnector.Points[0] != this.EditPoints[0].Location); 
            }
        } 
 
        public bool IsConnectorEndBeingMoved
        { 
            get
            {
                return (this.BeingEdited && this.activeEditPoint.Type == EditPoint.EditPointTypes.ConnectionEditPoint
                    && this.editedConnector.Points[this.editedConnector.Points.Count - 1] != this.EditPoints[this.EditPoints.Count -1].Location); 
            }
        } 
 
        public Connector Connector
        { 
            get
            {
                return this.editedConnector;
            } 

            set 
            { 
                this.editedConnector = value;
            } 
        }

        List EditPoints
        { 
            get
            { 
                return this.editPoints; 
            }
        } 

        public List ConnectorEditorLocation
        {
            get 
            {
                return this.GetPointsFromEditPoints(); 
            } 
        }
 
        //If the result is true this method also sets the currently active edit point.
        public bool EditPointsHitTest(Point pt)
        {
            if (this.EditPoints.Count > 0) 
            {
                foreach (EditPoint editPoint in this.EditPoints) 
                { 
                    if (DesignerGeometryHelper.DistanceBetweenPoints(pt, editPoint.Location) <= EditPointHitTestRadius)
                    { 
                        this.activeEditPoint = editPoint;
                        return true;
                    }
                } 
            }
            return false; 
        } 

        //Connector editing is completed. This function saves the state of the connectorEditor into the corresponding connector. 
        //Returns whether the Editor was persisted or not. It might not be persisted if Connector end points do not lie on a designer.
        public bool Persist(Point finalSnappedPoint)
        {
            List segments = new List(); 
            this.Update(finalSnappedPoint);
            if (this.activeEditPoint.Type == EditPoint.EditPointTypes.ConnectionEditPoint) 
            { 
                return false;
            } 
            segments = this.GetPointsFromEditPoints();
            this.parentPanel.UpdateConnectorPoints(Connector, segments);
            this.activeEditPoint = null;
            RemoveAdorners(); 
            DisplayEditPoints();
            return true; 
        } 

        //The Connector editor is to be destroyed. Remove the adorners on the editor. activeEditPoint=null sets BeingEdited property to false. 
        public void Remove()
        {
            this.activeEditPoint = null;
            RemoveAdorners(); 
            this.EditPoints.Clear();
            this.Connector.IsSelected = false; 
            this.Connector = null; 
            this.parentPanel = null;
        } 

        //This method removes the existing adorner on the edited connector, updates the active edit points and creates new adorners.
        public void Update(Point newPoint)
        { 
            RemoveAdorners();
            UpdateEditPoints(newPoint); 
            Fx.Assert(this.activeEditPoint != null, "activeEditPoint is null"); 
            adornerLayer.Add(new EditPointAdorner(this, editedConnector, true));
        } 

        //Add edit points of specified type
        void AddEditPoints(EditPoint.EditPointTypes editPointType)
        { 
            if (editPointType == EditPoint.EditPointTypes.ConnectionEditPoint)
            { 
                if (this.editPoints.Count == 0 || !this.editPoints[0].Location.Equals(editedConnector.Points[0])) 
                {
                    this.editPoints.Insert(0, new EditPoint(this, EditPoint.EditPointTypes.ConnectionEditPoint, editedConnector.Points[0])); 
                }

                if (this.editPoints.Count < 2 || !this.editPoints[this.editPoints.Count - 1].Equals(editedConnector.Points[editedConnector.Points.Count - 1]))
                { 
                    editPoints.Add(new EditPoint(this, EditPoint.EditPointTypes.ConnectionEditPoint, editedConnector.Points[editedConnector.Points.Count - 1]));
                } 
            } 
            else if (editPointType == EditPoint.EditPointTypes.MultiSegmentEditPoint)
            { 
                if (this.editPoints.Count == 2)
                {
                    List segments = new List(this.editedConnector.Points);
                    if (segments.Count > 0) 
                    {
                        segments.RemoveAt(0); 
                        segments.RemoveAt(segments.Count - 1); 
                    }
 
                    for (int i = 0; i < segments.Count; i++)
                    {
                        this.editPoints.Insert(this.editPoints.Count - 1, new EditPoint(this, EditPoint.EditPointTypes.MultiSegmentEditPoint, segments[i]));
                    } 
                }
                else 
                { 
                    Fx.Assert(false, "EditPoints.Count is not 2.");
                } 
            }
        }

        void CreateEditPoints() 
        {
            this.editPoints.Clear(); 
 
            AddEditPoints(EditPoint.EditPointTypes.ConnectionEditPoint);
            AddEditPoints(EditPoint.EditPointTypes.MultiSegmentEditPoint); 

            bool validEditPoints = ValidateEditPoints();
            Fx.Assert(validEditPoints, "Validating EditPoints failed.");
        } 

        void DisplayEditPoints() 
        { 
            CreateEditPoints();
            adornerLayer = AdornerLayer.GetAdornerLayer(editedConnector); 
            Fx.Assert(adornerLayer != null, "AdornerLayer is null.");
            adornerLayer.Add(new EditPointAdorner(this, editedConnector, false));
        }
 
        //This method is called when editing is completed.
        //Hence it does not matter whether ActiveEditPoint remains in the collection this.EditPoints or not. 
        List GetPointsFromEditPoints() 
        {
            List segments = new List(); 
            //Connection end points will never be moved/removed in following two function calls. Hence passing null as retainPointList.
            RemoveEditPointSegmentsWithinTolerence(null);
            RemoveCoincidingEditPoints(null);
            for (int i = 0; i < this.EditPoints.Count; i++) 
            {
                segments.Add(this.EditPoints[i].Location); 
            } 
            return segments;
        } 

        void RemoveAdorners()
        {
            if (adornerLayer != null && editedConnector != null) 
            {
                Adorner[] adorners = adornerLayer.GetAdorners(editedConnector); 
                if (adorners != null) 
                {
                    foreach (Adorner adorner in adorners) 
                    {
                        adornerLayer.Remove(adorner);
                    }
                } 
            }
        } 
 
        //Remove points with same slope
        void RemoveCoincidingEditPoints() 
        {
            if (this.editPoints.Count < 2 ||
                this.editPoints[0].Type != EditPoint.EditPointTypes.ConnectionEditPoint ||
                this.editPoints[this.editPoints.Count - 1].Type != EditPoint.EditPointTypes.ConnectionEditPoint || 
                (this.activeEditPoint != null && this.activeEditPoint.Type == EditPoint.EditPointTypes.ConnectionEditPoint))
            { 
                return; 
            }
 
            //Create list of points to retain
            List editPointsToRetain = new List(this.editPoints.Count);
            for (int i = 0; i < this.editPoints.Count; i++)
            { 
                if (this.editPoints[i].Type != EditPoint.EditPointTypes.MultiSegmentEditPoint ||
                    this.editPoints[i] == this.activeEditPoint) 
                { 
                    editPointsToRetain.Add(this.editPoints[i]);
                } 
            }

            //Step1: Get rid of all the line segments which are within tolerance range
            RemoveEditPointSegmentsWithinTolerence(editPointsToRetain); 
            //Step2: We should make sure that the active edit point is always retained but those points which are coincidental are always removed
 
            RemoveCoincidingEditPoints(editPointsToRetain); 

            //Step3: Go thorugh each segment and ensure that there all the segments are either vertical or horizontal 
            for (int i = 0; i < this.editPoints.Count - 1; i++)
            {
                EditPoint current = this.editPoints[i];
                EditPoint next = this.editPoints[i + 1]; 

                double slope = DesignerGeometryHelper.SlopeOfLineSegment(current.Location, next.Location); 
                if (slope != 0 && slope != double.MaxValue) 
                {
                    Point location = (slope < 1) ? new Point(next.Location.X, current.Location.Y) : new Point(current.Location.X, next.Location.Y); 
                    this.editPoints.Insert(i + 1, new EditPoint(this, EditPoint.EditPointTypes.MultiSegmentEditPoint, location));
                }
            }
        } 

        void RemoveEditPointSegmentsWithinTolerence(List retainPointsList) 
        { 
            for (int i = 1; i < this.editPoints.Count - 1; i++)
            { 
                EditPoint previous = this.editPoints[i - 1];
                EditPoint current = this.editPoints[i];
                EditPoint next = this.editPoints[i + 1];
 
                if (retainPointsList==null || !retainPointsList.Contains(current))
                { 
                    double distance = DesignerGeometryHelper.DistanceOfLineSegments(new Point[] { previous.Location, current.Location }); 
                    if (distance < ConnectorEditor.EditPointRadius && next.Type == EditPoint.EditPointTypes.MultiSegmentEditPoint)
                    { 
                        double slope = DesignerGeometryHelper.SlopeOfLineSegment(current.Location, next.Location);
                        next.Location = (slope < 1) ? new Point(next.Location.X, previous.Location.Y) : new Point(previous.Location.X, next.Location.Y);
                        this.editPoints.Remove(current);
                        i -= 1; 
                    }
                    else 
                    { 
                        distance = DesignerGeometryHelper.DistanceOfLineSegments(new Point[] { current.Location, next.Location });
                        if (distance < ConnectorEditor.EditPointRadius && previous.Type == EditPoint.EditPointTypes.MultiSegmentEditPoint) 
                        {
                            double slope = DesignerGeometryHelper.SlopeOfLineSegment(previous.Location, current.Location);
                            previous.Location = (slope < 1) ? new Point(previous.Location.X, next.Location.Y) : new Point(next.Location.X, previous.Location.Y);
                            this.editPoints.Remove(current); 
                            i--;
                        } 
                    } 
                }
            } 

        }

        void RemoveCoincidingEditPoints(List retainPointsList) 
        {
            for (int i = 1; i < this.EditPoints.Count - 1; i++) 
            { 
                EditPoint current = this.EditPoints[i];
                if (retainPointsList == null || !retainPointsList.Contains(current)) 
                {
                    EditPoint previous = this.EditPoints[i - 1];
                    EditPoint next = this.EditPoints[i + 1];
                    double slope1 = DesignerGeometryHelper.SlopeOfLineSegment(previous.Location, current.Location); 
                    double slope2 = DesignerGeometryHelper.SlopeOfLineSegment(current.Location, next.Location);
                    if (Math.Abs(slope1) == Math.Abs(slope2)) 
                    { 
                        this.EditPoints.Remove(current);
                        i -= 1; 
                    }
                }
            }
        } 

        //Remove edit points of specified type 
        //This method does not remove this.activeEditPoint. 
        void RemoveEditPoints(EditPoint.EditPointTypes editPointType)
        { 
            List editPointsToRemove = new List();
            for (int i = 0; i < this.editPoints.Count; i++)
            {
                EditPoint editPoint = this.editPoints[i]; 
                if (editPoint.Type == editPointType)
                { 
                    editPointsToRemove.Add(editPoint); 
                }
            } 

            for (int i = 0; i < editPointsToRemove.Count; i++)
            {
                EditPoint editPoint = editPointsToRemove[i]; 
                if (editPoint != this.activeEditPoint)
                { 
                    this.editPoints.Remove(editPoint); 
                }
            } 
        }

        void UpdateEditPoints(Point newPoint)
        { 
            if (this.editPoints.Count < 2 ||
                this.editPoints[0].Type != EditPoint.EditPointTypes.ConnectionEditPoint || 
                this.editPoints[this.editPoints.Count - 1].Type != EditPoint.EditPointTypes.ConnectionEditPoint) 
            {
                Fx.Assert(false, "EditPoints are invalid"); 
                return;
            }
            //STEP1: First we delete all the midsegmentpoints except the one which is being edited for simplicity
 
            //STEP2: Update points as per the type of edit point
            if (this.activeEditPoint != null) 
            { 
                int activeEditPointIndex = this.editPoints.IndexOf(this.activeEditPoint);
                EditPoint previous = (activeEditPointIndex > 0) ? this.editPoints[activeEditPointIndex - 1] : null; 
                EditPoint next = (activeEditPointIndex < this.editPoints.Count - 1) ? this.editPoints[activeEditPointIndex + 1] : null;

                //Note that extra edit points are only added if we are connected to connection point
                if (previous != null && previous.Type == EditPoint.EditPointTypes.ConnectionEditPoint) 
                {
                    double slopeOfLine = DesignerGeometryHelper.SlopeOfLineSegment(previous.Location, this.activeEditPoint.Location); 
                    Orientation orientation = (Math.Abs(slopeOfLine) < 1) ? Orientation.Horizontal : Orientation.Vertical; 

                    int editPointOffset = Convert.ToInt32(DesignerGeometryHelper.DistanceBetweenPoints(previous.Location, (next != null) ? next.Location : this.activeEditPoint.Location)) / 4; 
                    if (orientation == Orientation.Horizontal)
                    {
                        editPointOffset *= (previous.Location.X < this.activeEditPoint.Location.X) ? 1 : -1;
                    } 
                    else
                    { 
                        editPointOffset *= (previous.Location.Y < this.activeEditPoint.Location.Y) ? 1 : -1; 
                    }
 
                    activeEditPointIndex = this.editPoints.IndexOf(this.activeEditPoint);
                    Point editPointLocation = (orientation == Orientation.Horizontal) ? new Point(previous.Location.X + editPointOffset, previous.Location.Y) : new Point(previous.Location.X, previous.Location.Y + editPointOffset);
                    previous = new EditPoint(this, EditPoint.EditPointTypes.MultiSegmentEditPoint, editPointLocation);
                    this.editPoints.InsertRange(activeEditPointIndex, new EditPoint[] { new EditPoint(this, EditPoint.EditPointTypes.MultiSegmentEditPoint, editPointLocation), previous }); 
                }
 
                if (next != null && next.Type == EditPoint.EditPointTypes.ConnectionEditPoint) 
                {
                    double slopeOfLine = DesignerGeometryHelper.SlopeOfLineSegment(this.activeEditPoint.Location, next.Location); 
                    Orientation orientation = (Math.Abs(slopeOfLine) < 1) ? Orientation.Horizontal : Orientation.Vertical;

                    int editPointOffset = Convert.ToInt32(DesignerGeometryHelper.DistanceBetweenPoints((previous != null) ? previous.Location : this.activeEditPoint.Location, next.Location)) / 4;
                    if (orientation == Orientation.Horizontal) 
                    {
                        editPointOffset *= (this.activeEditPoint.Location.X < next.Location.X) ? -1 : 1; 
                    } 
                    else
                    { 
                        editPointOffset *= (this.activeEditPoint.Location.Y < next.Location.Y) ? -1 : 1;
                    }

                    activeEditPointIndex = this.editPoints.IndexOf(this.activeEditPoint); 
                    Point editPointLocation = (orientation == Orientation.Horizontal) ? new Point(next.Location.X + editPointOffset, next.Location.Y) : new Point(next.Location.X, next.Location.Y + editPointOffset);
                    next = new EditPoint(this, EditPoint.EditPointTypes.MultiSegmentEditPoint, editPointLocation); 
                    this.editPoints.InsertRange(activeEditPointIndex + 1, new EditPoint[] { next, new EditPoint(this, EditPoint.EditPointTypes.MultiSegmentEditPoint, editPointLocation) }); 
                }
 
                //STEP2: UPDATE THE EDIT POINTS
                if (this.activeEditPoint.Type == EditPoint.EditPointTypes.ConnectionEditPoint)
                {
                    Fx.Assert(this.editPoints[0].Type == EditPoint.EditPointTypes.ConnectionEditPoint, "EditPoint type is wrong."); 
                    Fx.Assert(this.editPoints[editPoints.Count - 1].Type == EditPoint.EditPointTypes.ConnectionEditPoint, "EditPoint type is wrong.");
                    this.activeEditPoint.Location = newPoint; 
 
                    Point begin, end;
                    Fx.Assert(this.editPoints.Count > 0, "Some edit point should exist"); 
                    begin = this.editPoints[0].Location;
                    end = this.editPoints[this.editPoints.Count - 1].Location;

                    //When we start editing the end point we need to clear the slate and start over 
                    List newEditPoints = new List();
                    Point[] points = ConnectorRouter.Route(parentPanel, begin, end); 
                    if (points != null && points.Length > 1) 
                    {
                        RemoveEditPoints(EditPoint.EditPointTypes.MultiSegmentEditPoint); 
                        for (int i = 1; i < points.Length - 1; ++i)
                        {
                            newEditPoints.Add(new EditPoint(this, EditPoint.EditPointTypes.MultiSegmentEditPoint, points[i]));
                        } 
                        this.editPoints.InsertRange(1, newEditPoints.ToArray());
                    } 
                } 
                else if (this.activeEditPoint.Type == EditPoint.EditPointTypes.MultiSegmentEditPoint)
                { 
                    if (previous != null && previous.Type != EditPoint.EditPointTypes.ConnectionEditPoint && next != null && next.Type != EditPoint.EditPointTypes.ConnectionEditPoint)
                    {
                        //Update the previous point
                        double slopeOfLine = DesignerGeometryHelper.SlopeOfLineSegment(previous.Location, this.activeEditPoint.Location); 
                        Orientation orientation = (Math.Abs(slopeOfLine) < 1) ? Orientation.Horizontal : Orientation.Vertical;
                        previous.Location = (orientation == Orientation.Horizontal) ? new Point(previous.Location.X, newPoint.Y) : new Point(newPoint.X, previous.Location.Y); 
 
                        //Update the next point
                        slopeOfLine = DesignerGeometryHelper.SlopeOfLineSegment(this.activeEditPoint.Location, next.Location); 
                        orientation = (Math.Abs(slopeOfLine) < 1) ? Orientation.Horizontal : Orientation.Vertical;
                        next.Location = (orientation == Orientation.Horizontal) ? new Point(next.Location.X, newPoint.Y) : new Point(newPoint.X, next.Location.Y);

                        //Update the current point 
                        this.activeEditPoint.Location = newPoint;
                    } 
                    else 
                    {
                        Fx.Assert(false, "Should not be here. UpdateEditPoints failed."); 
                    }
                }
            }
 
            //STEP3: Remove all the redundant edit points
            RemoveCoincidingEditPoints(); 
 
            //STEP4: Add back the segment mid points
            //AddEditPoints(EditPoint.EditPointTypes.MidSegmentEditPoint); 

            bool validEditPoints = ValidateEditPoints();
            Fx.Assert(validEditPoints, "Validating EditPoints failed.");
        } 

        bool ValidateEditPoints() 
        { 
            if (this.editPoints.Count < 2)
            { 
                return false;
            }

            return true; 
        }
 
 

        class EditPoint 
        {
            EditPointTypes editPointType;
            ConnectorEditor owner;
            Point point; 

            public EditPoint(ConnectorEditor owner, EditPointTypes editPointType, Point point) 
            { 
                this.owner = owner;
                this.editPointType = editPointType; 
                this.point = point;
            }

            public Point Location 
            {
                get 
                { 
                    return this.point;
                } 

                set
                {
                    this.point = value; 
                }
            } 
 
            public EditPointTypes Type
            { 
                get
                {
                    return this.editPointType;
                } 
            }
            public enum EditPointTypes 
            { 
                ConnectionEditPoint = 1, MultiSegmentEditPoint
            } 
            ;

        }
 
        sealed class EditPointAdorner : Adorner
        { 
            ConnectorEditor adornedEditor; 
            bool drawLines;
 
            public EditPointAdorner(ConnectorEditor cEditor, UIElement adornedElement, bool shouldDrawLines)
                : base(adornedElement)
            {
                Fx.Assert(adornedElement != null, "Adorned element is null."); 
                adornedEditor = cEditor;
                this.IsHitTestVisible = false; 
                this.drawLines = shouldDrawLines; 
            }
 
            protected override void OnRender(DrawingContext drawingContext)
            {
                int i = 0;
                SolidColorBrush renderBrush = new SolidColorBrush(WorkflowDesignerColors.WorkflowViewElementSelectedBackgroundColor); 
                renderBrush.Opacity = FreeFormPanel.ConnectorEditorOpacity;
                Pen renderPen = new Pen(new SolidColorBrush(WorkflowDesignerColors.WorkflowViewElementSelectedBorderColor), FreeFormPanel.ConnectorEditorThickness); 
                double renderRadius = ConnectorEditor.EditPointRadius; 
                for (i = 0; i < adornedEditor.EditPoints.Count -1 ; i++)
                { 
                    drawingContext.DrawEllipse(renderBrush, renderPen, adornedEditor.EditPoints[i].Location, renderRadius, renderRadius);
                    if (drawLines)
                    {
                        drawingContext.DrawLine(renderPen, adornedEditor.EditPoints[i].Location, adornedEditor.EditPoints[i + 1].Location); 
                    }
                } 
                drawingContext.DrawEllipse(renderBrush, renderPen, adornedEditor.EditPoints[i].Location, renderRadius, renderRadius); 
                base.OnRender(drawingContext);
                Keyboard.Focus(adornedEditor.Connector); 
            }
        }
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK