public void DeleteLastSegment(SMPathOut firstSeg) { // Never delete the first one. SMPathSegment thisPathSeg = firstSeg.Next; int nSeg = 1; while (thisPathSeg != null) { if (thisPathSeg.Next == null) { // Delete this one SegmentCtl segCtl = GetSegmentCtl(thisPathSeg); if (segCtl != null) { _containerPanel.Controls.Remove(segCtl); segCtl.Dispose(); } thisPathSeg.Delete(); PreMoveIt(firstSeg); return; } thisPathSeg = thisPathSeg.Next; nSeg++; } }
protected virtual void PreRun() { try { if (!_isAlreadyPreRun) { if (stateMachine == null) { stateMachine = StateMachine; } _timeoutHandle.Reset(); waitHandle = stateMachine.WaitHandle; decisionWaitHandle = stateMachine.DecisionWaitHandle; decisionLoopList = stateMachine.DecisionLoopList; pathOut = null; flowItemForPathOut = null; _decisionTimeout = -1; ExitFlowItem(); FindStart(); EnterFlowItem(); _isAlreadyPreRun = true; } } catch { _isAlreadyPreRun = false; } }
/// <summary> /// Move just one single segment path /// </summary> /// <param name="pathOut"></param> public void MoveIt(SMPathOut pathOut) { //Do No Any GUI on Production Run for Beeter Performance /* * if (pathOut != null && !(pathOut is SMPathOutPlug)) * { * * if(DateTime.Now > _lastUpdate) * { * PointF endGridPt = MoveSegment(pathOut, _flowItem.GridLoc); * //Add the arrow.Either at the beginning or end * MoveArrow(pathOut); * * * if (pathOut is SMPathOutBool) * { * SMPathOutBool pathOutBool = pathOut as SMPathOutBool; * MoveYesNo(_flowItem[pathOut], BuildLabelName(pathOutBool.True)); * } * * _lastUpdate = DateTime.Now.AddTicks(_updateMs * 10000); * * } * } */ }
/// <summary> /// Get the flow item for the target in the specified pathOut /// </summary> /// <param name="pathOut"></param> /// <returns></returns> public SMFlowBase GetFlowTarget(SMPathOut pathOut) { if (pathOut.HasTargetID) { SMFlowBase[] list = null; if (!pathOut.TargetID.Contains(".")) { //list = FilterByType<SMFlowBase>(); list = pathOut.Owner.Parent.FilterByType <SMFlowBase>(); } //Sport Transition else { SMFlowBase smPathOut = U.GetComponent(pathOut.TargetID) as SMFlowBase; return(smPathOut); } if (list.Length > 0) { try { return(list.First(c => c.Name == pathOut.TargetID)); } catch { pathOut.DeletedTarget(); } } } return(null); }
protected virtual void Build(SMPathOut pathOut) { if (!(pathOut is SMPathOutPlug)) { BuildSegment(pathOut); ArrowCtl arrowCtl = new ArrowCtl(_containerPanel, ArrowName(pathOut)); _containerPanel.Controls.Add(arrowCtl); } }
/// <summary> /// Move the arrow to the right position /// </summary> /// <param name="flowItem"></param> /// <param name="pathOut"></param> public void MoveIt(SMFlowBase flowItem, SMPathOut pathOut) { try { _ctrlBasefromPathOut = _containerPanel.GetFlowCtl(pathOut.Owner.Name); _ctlBaseTgt = _containerPanel.GetFlowCtl(pathOut.TargetID); if (_ctlBaseTgt == null) { return; } Size arrowSize = global::MCore.Comp.SMLib.SMFlowChart.Properties.Resources.ArrowUp.Size; Point borderLocation = _ctlBaseTgt.Location; Size borderSize = _ctlBaseTgt.Size; borderLocation.Offset(-arrowSize.Width, -arrowSize.Height); borderSize.Width += arrowSize.Width; borderSize.Height += arrowSize.Height; Rectangle rcBorder = new Rectangle(borderLocation, borderSize); PointF endPt = flowItem.FindEndPoint(pathOut); Point pixXY = SMContainerPanel.GridToPixel(endPt); SMPathSegment pathLastSeg = pathOut.Last; if (pathLastSeg.Vertical) { if (pathLastSeg.GridDistance < 0) { // Up SetBackgroundImage(global::MCore.Comp.SMLib.SMFlowChart.Properties.Resources.ArrowUp); Location = new Point(pixXY.X - arrowSize.Width / 2, rcBorder.Bottom); } else { // Down SetBackgroundImage(global::MCore.Comp.SMLib.SMFlowChart.Properties.Resources.ArrowDown); Location = new Point(pixXY.X - arrowSize.Width / 2, rcBorder.Top); } } else { if (pathLastSeg.GridDistance < 0) { // Left SetBackgroundImage(global::MCore.Comp.SMLib.SMFlowChart.Properties.Resources.ArrowLeft); Location = new Point(rcBorder.Right, pixXY.Y - arrowSize.Height / 2); } else { // Right SetBackgroundImage(global::MCore.Comp.SMLib.SMFlowChart.Properties.Resources.ArrowRight); Location = new Point(rcBorder.Left, pixXY.Y - arrowSize.Height / 2); } } _ctrlBasefromPathOut.LocationChanged += new EventHandler(ctrlBasefromPathOut_OnLocationChanged); _locOfstFromCtrlBase = new Point(_ctrlBasefromPathOut.Location.X - this.Location.X, _ctrlBasefromPathOut.Location.Y - this.Location.Y); Show(); } catch (Exception ex) { ex.ToString(); } }
/// <summary> /// Returns true if this segment path is selected /// </summary> /// <param name="pathOut"></param> /// <returns></returns> public bool IsSelected(SMPathOut pathOut) { SegmentCtl segCtl = GetSegmentCtl(pathOut); if (segCtl != null) { return((segCtl as ISelectable).SMSelected); } return(false); }
private string GetSegTypeName(SMPathSegment pathSeg) { SMPathOut pathSegOut = pathSeg.First; string typeName = typeName = pathSegOut.GetType().Name.Substring(6); if (pathSegOut is SMPathOutBool) { typeName += (pathSegOut as SMPathOutBool).ID; } return(typeName); }
private void Dispose(SMPathOut pathOut) { if (pathOut != null && !(pathOut is SMPathOutPlug)) { DisposeSegment(pathOut); string arrowName = ArrowName(pathOut); if (_containerPanel.Controls.ContainsKey(arrowName)) { ArrowCtl arrowCtl = _containerPanel.Controls[arrowName] as ArrowCtl; _containerPanel.Controls.Remove(arrowCtl); arrowCtl.Dispose(); } } }
public eDir this[SMPathOut pathOutCheck] { get { for (eDir dir = eDir.Up; dir < eDir.Num; dir++) { if (object.ReferenceEquals(this[dir], pathOutCheck)) { return(dir); } } return(eDir.Num); } }
public void PreMoveIt(SMPathOut pathOut) { if (pathOut != null && !(pathOut is SMPathOutPlug)) { PointF endGridPt = MoveSegment(pathOut, _flowItem.GridLoc); // Add the arrow. Either at the beginning or end MoveArrow(pathOut); if (pathOut is SMPathOutBool) { SMPathOutBool pathOutBool = pathOut as SMPathOutBool; MoveYesNo(_flowItem[pathOut], BuildLabelName(pathOutBool.True)); } } }
public void Call() { lock (_locker) { SMPathOut smOut = Run(); if (smOut is SMPathOutStop || smOut == null) { StateMachine.ReceivedStop = true; } else if (smOut is SMPathOutError) { // Already logged throw new Exception(); } } }
/// <summary> /// Evaluate specific path for target /// </summary> /// <param name="pathOut"></param> public void DetermineTarget(SMPathOut pathOut) { if (!(pathOut is SMPathOutPlug)) { // Allow us to loop back to self only if there is more than one segment SMFlowBase searcher = pathOut.Next != null ? this : null; SMFlowBase flowItem = ParentContainer.FindTarget(searcher, FindEndPoint(pathOut)); if (flowItem != null) { pathOut.TargetID = flowItem.Name; } else { pathOut.TargetID = string.Empty; } } }
private void MoveArrow(SMPathOut pathOut) { string name = ArrowName(pathOut); if (_containerPanel.Controls.ContainsKey(name)) { ArrowCtl arrowCtl = _containerPanel.Controls[name] as ArrowCtl; if (IsSelected(pathOut) || !pathOut.HasTargetID) { arrowCtl.Hide(); return; } // It has a target and is not selected arrowCtl.MoveIt(_flowItem, pathOut); } }
protected override void Build(SMPathOut pathOut) { base.Build(pathOut); if (pathOut is SMPathOutBool) { SMPathOutBool pathOutBool = pathOut as SMPathOutBool; YesNoLabel tbYesNo = new YesNoLabel(this, pathOutBool); tbYesNo.BackColor = System.Drawing.Color.Transparent; tbYesNo.Name = BuildLabelName((pathOutBool).True); tbYesNo.Size = new System.Drawing.Size(16, 16); tbYesNo.TabIndex = 0; tbYesNo.Text = pathOutBool.Text; tbYesNo.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; tbYesNo.Click += new EventHandler(tbYesNo_Click); tbYesNo.MouseMove += new MouseEventHandler(OnMouseMove); _containerPanel.Controls.Add(tbYesNo); } }
/// <summary> /// Get the end point of a path /// </summary> /// <param name="pathOut"></param> /// <returns></returns> public PointF FindEndPoint(SMPathOut pathOut) { return(pathOut.FindEndPoint(GridLoc)); }
/// <summary> /// Returns the path to take from here /// </summary> /// <returns></returns> public override SMPathOut Run() { lock (this) { if (HasChildren || HasTransition) { if (NeedsRebuild) { //Rebuild(); } if (HasMethod) { //For dry run if (CompMachine.s_machine.IsDryRun && this.DryRunSkipActions) { // Do no action } else { //Run All Method //validMethods.ForEach(c => c.RunAsync()); Parallel.ForEach(validMethods, method => method.RunAsync()); //// Wait until they all complete WaitHandle.WaitAll(waitHandles); } } // Look for any exceptions made by the methods List <Exception> exceptions = new List <Exception>(); foreach (SMMethod method in validMethods) { if (method.methodResults.Exception != null) { exceptions.Add(method.methodResults.Exception); } } //Parallel.ForEach(validMethods, method => //{ // if (method.methodResults.Exception != null) // { // exceptions.Add(method.methodResults.Exception); // } //}); if (exceptions.Count > 0) { // We found at least one exception. Store it with the SMPathOutError SMPathOutError pathError = this[typeof(SMPathOutError)] as SMPathOutError; if (pathError != null) { pathError.Exceptions = exceptions; return(pathError); } } if (HasTransition) { bool anyTransPassValidate = false; do { var waitDelay = Task.Delay(10); if (TransTimeOut > 0 && !_stopWatch.IsRunning) { _stopWatch.Restart(); } //Run All Transition validTransitions.ForEach(c => c.RunAsync()); //Parallel.ForEach(validTransitions, transition => transition.RunAsync()); //Wait until all transition run complete WaitHandle.WaitAll(waitHandlesTransitions, 1000); foreach (SMTransition transition in validTransitions) { anyTransPassValidate = anyTransPassValidate || transition.ValidationResult; if (transition.TransitionResults.Exception != null) { exceptions.Add(transition.TransitionResults.Exception); } } //Parallel.ForEach(validTransitions, transition => //{ // anyTransPassValidate = anyTransPassValidate || transition.ValidationResult; // if (transition.TransitionResults.Exception != null) // { // exceptions.Add(transition.TransitionResults.Exception); // } //}); //For dry run if (CompMachine.s_machine.IsDryRun && this.UseDryRunTrans && this.DryRunTransitionTargetID != "") { anyTransPassValidate = true; } if (exceptions.Count > 0) { // We found at least one exception. Store it with the SMPathOutError SMPathOutError pathError = this[typeof(SMPathOutError)] as SMPathOutError; if (pathError != null) { pathError.Exceptions = exceptions; return(pathError); } } //Validate Timeout if (TransTimeOut > 0 && !anyTransPassValidate && (_stopWatch.ElapsedMilliseconds > TransTimeOut)) { SMPathOut stopPath = this[typeof(SMPathOutStop)]; //Display message in case no path error connected if (stopPath == null || !stopPath.HasTargetID || !FlowTimeoutToStopPath) { string caption = TimeOutCaption; if (caption == "") { caption = "Transition TimeOut"; } string msg = TimeOutMessage; if (msg == "") { msg = String.Format("Transition TimeOut [{0}] on state [{1}]", this.PathText, this.StateMachine); } _stopWatch.Stop(); _timeoutHandle.Reset(); DisplayAsynchMsg(msg, caption); _timeoutHandle.WaitOne(); _timeoutHandle.Reset(); } else { _stopWatch.Stop(); _timeoutHandle.Reset(); return(this[typeof(SMPathOutStop)]); } } waitDelay.Wait(); }while (!anyTransPassValidate && LoopTransitions && !StateMachine.ReceivedStop); } _stopWatch.Stop(); _timeoutHandle.Reset(); } if (!StateMachine.ReceivedStop) { //For dry run if (CompMachine.s_machine.IsDryRun && this.UseDryRunTrans && this.DryRunTransitionTargetID != "") { _dryRunPath.TargetID = this.DryRunTransitionTargetID; _dryRunPath.Initialize(this, true); return(_dryRunPath); } //Check First OK Transition Path Out foreach (SMTransition transition in validTransitions) { if (transition.ValidationResult && transition.TransitionPath.TargetID != "") { return(transition.TransitionPath); } } } } // Only one out return(this[typeof(SMPathOut)]); }
public void AddToDecisionList(SMDecision decisionItem, SMFlowBase flowItemForPathOut, SMPathOut pathOut) { _decisionLoopList.Add(decisionItem); _pathLoopDict.Add(pathOut, flowItemForPathOut); }
private string ArrowName(SMPathOut pathOut) { return(string.Format("{0}-{1}-Arrow", this.Name, GetSegTypeName(pathOut))); }
/// <summary> /// Rebuild the segment /// </summary> /// <param name="pathOut"></param> public void RebuildSegment(SMPathOut pathOut) { Dispose(pathOut); Build(pathOut); PreMoveIt(pathOut); }
public override SMPathOut Run() { lock (this) { if (HasChildren) { do { var waitDelay = Task.Delay(10); if (TransTimeOut > 0 && !_stopWatch.IsRunning) { _stopWatch.Restart(); } try { if (this.HasChildren) { ValidationResult = (this.ChildArray[0] as SMSubCondBase).Validate(); } //For dry run if (CompMachine.s_machine.IsDryRun && this.UseDryRunTrans && this.DryRunTransitionTargetID != "") { ValidationResult = true; _dryRunPath.TargetID = this.DryRunTransitionTargetID; _dryRunPath.Initialize(this, true); return(_dryRunPath); } if (ValidationResult && _transitionPath.TargetID != "") { return(_transitionPath); } } catch (Exception ex) { _stopWatch.Stop(); _timeoutHandle.Reset(); // We found at least one exception. Store it with the SMPathOutError SMPathOutError pathError = this[typeof(SMPathOutError)] as SMPathOutError; if (pathError != null) { pathError.Exceptions.Add(ex); return(pathError); } } //Validate Timeout if (TransTimeOut > 0 && !ValidationResult && (_stopWatch.ElapsedMilliseconds > TransTimeOut)) { SMPathOut stopPath = this[typeof(SMPathOutStop)]; //Display message in case no path error connected if (stopPath == null || !stopPath.HasTargetID || !FlowTimeoutToStopPath) { string caption = TimeOutCaption; if (caption == "") { caption = "Transition TimeOut"; } string msg = TimeOutMessage; if (msg == "") { msg = String.Format("Transition TimeOut [{0}] on state [{1}]", this.PathText, this.StateMachine); } _stopWatch.Stop(); _timeoutHandle.Reset(); DisplayAsynchMsg(msg, caption); _timeoutHandle.WaitOne(); _timeoutHandle.Reset(); } else { _stopWatch.Stop(); _timeoutHandle.Reset(); return(this[typeof(SMPathOutStop)]); } } waitDelay.Wait(); } while (!ValidationResult && LoopTransition && !StateMachine.ReceivedStop); _stopWatch.Stop(); _timeoutHandle.Reset(); } //Always true if no any condition in child array else { ValidationResult = true; if (ValidationResult && _transitionPath.TargetID != "") { return(_transitionPath); } } } // Only one out return(this[typeof(SMPathOut)]); }
/// <summary> /// Set this path to be selected /// </summary> /// <param name="pathOut"></param> public void SetSelected(SMPathOut pathOut) { SegmentCtl segCtl = GetSegmentCtl(pathOut); _containerPanel.CurrentSel = segCtl as ISelectable; }
/// <summary> /// Run method for the main state machine thread /// </summary> /// <returns></returns> public override SMPathOut Run() { //SMStateMachine stateMachine = StateMachine; try { //_timeoutHandle.Reset(); //ManualResetEvent waitHandle = stateMachine.WaitHandle; //ManualResetEvent decisionWaitHandle = stateMachine.DecisionWaitHandle; //List<SMDecision> decisionLoopList = stateMachine.DecisionLoopList; //SMPathOut pathOut = null; //SMFlowBase flowItemForPathOut = null; //_decisionTimeout = -1; //ExitFlowItem(); //FindStart(); //// Hightlight start //EnterFlowItem(); PreRun(); while (true) { Thread.Sleep(0); // If Reset will block thread (Pause) until Step or Run (Set) if (stateMachine.Mode == SMStateMachine.eMode.Pause) { waitHandle.Reset(); // Wait until(Pause) until Step or Run (Set) EnterFlowItem(); waitHandle.WaitOne(); ExitFlowItem(); } if (_currentFlowItem is SMDecision) { SMDecision decisionItem = _currentFlowItem as SMDecision; if (decisionLoopList.Contains(decisionItem)) { // We have closed the loop of nothing but decision items EnterFlowItem(); //stateMachine.EnterPathItem(flowItemForPathOut, flowItemForPathOut.OutgoingPath); // Modify by Kasem 12-Feb-2018 if (decisionItem.WaitTimeoutMS <= 0) { decisionWaitHandle.WaitOne(_decisionTimeout); } else { Boolean signal = false; signal = decisionWaitHandle.WaitOne(decisionItem.WaitTimeoutMS); //Trigger Timeout if (!signal) { _timeoutHandle.Set(); } } //-------------------------------- _decisionTimeout = -1; //stateMachine.ExitPathItem(flowItemForPathOut, flowItemForPathOut.OutgoingPath); ExitFlowItem(); stateMachine.ClearDecisionList(); } else { if (decisionLoopList.Count == 0) { // First one. Reset early in case something changes quickly decisionWaitHandle.Reset(); } decisionItem.AddNotifier(StateMachine.OnDecisionChanged); stateMachine.AddToDecisionList(decisionItem, flowItemForPathOut, pathOut); } } else { stateMachine.ClearDecisionList(); } // // Run this item // //Dump Process Usage Timing if (CompMachine.s_machine.ProcessUsageTrigger) { if (!(_currentFlowItem is SMFlowContainer)) { StateMachine.AddTimingElement(">Run: " + _currentFlowItem.Text); } else { StateMachine.AddTimingElement(">Enter: " + _currentFlowItem.Text); } } EnterFlowItem(); pathOut = _currentFlowItem.Run(); ExitFlowItem(); //Dump Process Usage Timing if (CompMachine.s_machine.ProcessUsageTrigger) { if (!(_currentFlowItem is SMFlowContainer)) { StateMachine.AddTimingElement("<Run: " + _currentFlowItem.Text); } else { StateMachine.AddTimingElement("<Exit: " + _currentFlowItem.Text); } } //Add by Kasem 12-Feb-2018 if (_currentFlowItem is SMDecision) { //Determine Start to Capture Timeout SMDecision decisionItem = _currentFlowItem as SMDecision; //No Partout Meaning Waiting Condition if (pathOut != null && !pathOut.HasTargetID && decisionItem.WaitTimeoutMS > 0) { //Start Stop watch if Nested Condition if (!_stopWatch.IsRunning && _currentFlowItem.HasChildren) { _stopWatch.Restart(); } else if (_stopWatch.IsRunning && !_currentFlowItem.HasChildren) { _stopWatch.Stop(); } else { if ((_currentFlowItem.HasChildren) && (_stopWatch.ElapsedMilliseconds > decisionItem.WaitTimeoutMS) || (!_currentFlowItem.HasChildren) && _timeoutHandle.WaitOne(0)) { //Check Stop Path and Flow to Timeout Flag SMPathOut stopPath = _currentFlowItem[typeof(SMPathOutStop)]; //Popup in case no path for Timeout if (!decisionItem.FlowTimeoutToStopPath || stopPath == null || !stopPath.HasTargetID) { U.LogWarning("Decision Wait Time Out [{0}] on state [{1}]", decisionItem.PathText, this.StateMachine); string msg = String.Format("Decision Wait Time Out [{0}] on state [{1}]", decisionItem.PathText, this.StateMachine); _stopWatch.Stop(); _timeoutHandle.Reset(); DisplayAsynchMsg(msg); _timeoutHandle.WaitOne(); _timeoutHandle.Reset(); } //Case Timeout path available else { _stopWatch.Stop(); _timeoutHandle.Reset(); pathOut = stopPath; } } } } //Force pathout to null incase of pathout is stop path but we use FlowTimeoutToStopPath option else if (pathOut is SMPathOutStop && decisionItem.FlowTimeoutToStopPath) { pathOut = null; _stopWatch.Stop(); } //Stop capture time in case decision meet wait condition else { _stopWatch.Stop(); } } //Modify by Kasem 13-Feb-2018 if (stateMachine.ReceivedStop) { if (!(_currentFlowItem is SMDecision) && !(_currentFlowItem is SMTransition) && !(_currentFlowItem is SMActTransFlow)) { stateMachine.ReceivedStop = false; // Redirect the path to the PathOutStop pathOut = _currentFlowItem[typeof(SMPathOutStop)]; } else { stateMachine.ReceivedStop = false; _stopWatch.Stop(); if (_currentFlowItem is SMDecision) { if (!(_currentFlowItem as SMDecision).FlowTimeoutToStopPath) { pathOut = _currentFlowItem[typeof(SMPathOutStop)]; } else { pathOut = null; } } else if (_currentFlowItem is SMTransition) { if (!(_currentFlowItem as SMTransition).FlowTimeoutToStopPath) { pathOut = _currentFlowItem[typeof(SMPathOutStop)]; } else { pathOut = null; } } else if (_currentFlowItem is SMActTransFlow) { if (!(_currentFlowItem as SMActTransFlow).FlowTimeoutToStopPath) { pathOut = _currentFlowItem[typeof(SMPathOutStop)]; } else { pathOut = null; } } } } //-------------------------------- if (pathOut == null) { // Will stop the whole State Machine return(null); } SMPathOutError pathOutError = pathOut as SMPathOutError; if (pathOutError != null) { pathOutError.ProcessErrors(); } if (pathOut.HasTargetID) { flowItemForPathOut = _currentFlowItem; // We are on the target path. _currentFlowItem = GetFlowTarget(pathOut); _currentFlowItem.IncomingPath = pathOut; } else if ((_currentFlowItem is SMDecision) && !(pathOut is SMPathOutStop) && !(pathOut is SMPathOutError)) { // Keep same current flow item. Let it loop to itself } else { // No target to go to // Will stop the whole State Machine if ((pathOut is SMPathOutStop) || (pathOut is SMPathOutError)) { if (!FindStop()) { FindStart(); } EnterFlowItem(); } _currentFlowItem.IncomingPath = null; return(null); } if (_currentFlowItem == null) { throw new Exception(string.Format("Could not locate Flowitem from ID '{0}' in StateMachine '{1}'. State Machine has paused.", pathOut.TargetID, Text)); } if (_currentFlowItem is SMExit) { EnterFlowItem(); if (this is SMDecision) { foreach (SMPathOut path in PathArray) { if (_currentFlowItem is SMReturnNo) { if (path is SMPathOutBool && !(path as SMPathOutBool).True) { return(path); } } else if (_currentFlowItem is SMReturnYes) { if (path is SMPathOutBool && (path as SMPathOutBool).True) { return(path); } } else if (_currentFlowItem is SMReturnStop) { if (path is SMPathOutStop) { return(path); } } } } if (this is SMSubroutine && _currentFlowItem is SMReturnStop) { return(this[typeof(SMPathOutStop)]); } return(this[typeof(SMPathOut)]); } }//End While True; } finally { stateMachine.ClearDecisionList(); _isAlreadyPreRun = false; System.Threading.Tasks.Task.Run(() => PreRun()); } }
public void ChangeExit(SMPathOut pathOut, int x, int y) { int directionVal = 0; eDir dirThis = this[pathOut]; switch (dirThis) { case eDir.Num: return; case eDir.Up: directionVal = Math.Sign(x); break; case eDir.Down: directionVal = -Math.Sign(x); break; case eDir.Right: directionVal = Math.Sign(y); break; case eDir.Left: directionVal = -Math.Sign(y); break; } if (directionVal == 0) { return; } // Loop to find next or previous empty spot eDir dirSwap = dirThis; do { if (directionVal > 0) { dirSwap++; if (dirSwap == eDir.Num) { dirSwap = eDir.Up; } } else { if (dirSwap == eDir.Up) { dirSwap = eDir.Left; } else { dirSwap--; } } if (this[dirSwap] is SMPathOutPlug) { // Got it this[dirThis] = this[dirSwap]; this[dirSwap] = pathOut; switch (dirSwap) { case eDir.Up: pathOut.GridDistance = -Math.Abs(pathOut.GridDistance); break; case eDir.Down: pathOut.GridDistance = Math.Abs(pathOut.GridDistance); break; case eDir.Right: pathOut.GridDistance = Math.Abs(pathOut.GridDistance); break; case eDir.Left: pathOut.GridDistance = -Math.Abs(pathOut.GridDistance); break; } pathOut.Initialize(this, IsVertical(dirSwap)); return; } } while (dirSwap != dirThis); }