public SMRect EnforceDocking(BorderNodeGeometry geometry) { float constrainedY = Math.Max(StructureThickness.Top, geometry.Bounds.Y); // _rect.Bottom already accounts for StructureThickness - see the constructor. constrainedY = Math.Min(constrainedY, _rect.Bottom - geometry.Bounds.Height); switch (geometry.Docking) { case BorderNodeDocking.Left: return(new SMRect(-EdgeOverflow, constrainedY, geometry.Bounds.Width, geometry.Bounds.Height)); case BorderNodeDocking.Right: return(new SMRect(_rect.Width - geometry.Bounds.Width + EdgeOverflow, constrainedY, geometry.Bounds.Width, geometry.Bounds.Height)); default: break; } return(geometry.Bounds); }
public BorderNodeGeometry ConstrainBounds(BorderNodeGeometry geom, RectDifference oldMinusNew) { // ShiftRegisters cannot change docking, so first force the geometry to dock, this coerces crazy X values SMRect coercedInput = EnforceDocking(geom); // Now we are going to iterate up and down the side of the structure, looking for a location in which // both the left and the right registers are clear. We start with the right being the coerced input // and the left being the actual left shift register's bounds _except_ it's Y, which we want to move in sync with it's pair SMRect rightBounds = coercedInput; SMRect leftBounds = PairedBeginLifetimeTunnel.Bounds; leftBounds.Y = rightBounds.Y; // Before we start scanning, make sure our current location doesn't just work, if it does we're done if (IsGood(leftBounds, rightBounds)) { return(new BorderNodeGeometry(rightBounds, BorderNodeDocking.Right)); } const float DistanceToIterateBy = StockDiagramGeometries.GridSize; SMRect rightSideUpIteration = rightBounds; rightSideUpIteration.Y -= DistanceToIterateBy; SMRect leftSideUpIteration = leftBounds; leftSideUpIteration.Y -= DistanceToIterateBy; SMRect rightSideDownIteration = rightBounds; rightSideDownIteration.Y += DistanceToIterateBy; SMRect leftSideDownIteration = leftBounds; leftSideDownIteration.Y += DistanceToIterateBy; bool favorUp = oldMinusNew.Y > 0 || oldMinusNew.X > 0; bool favorDown = oldMinusNew.Y < 0 || oldMinusNew.X < 0; bool favorNeither = !favorUp && !favorDown; // prevent overlap. Starting from our bounds calculation, move outward to find closest. Make sure we don't leave structure. while (true) { if (favorUp || favorNeither) { if (IsGood(leftSideUpIteration, rightSideUpIteration)) { return(new BorderNodeGeometry(rightSideUpIteration, BorderNodeDocking.Right)); } if (!IsInBounds(leftSideUpIteration, rightSideUpIteration)) { favorUp = false; } rightSideUpIteration.Y -= DistanceToIterateBy; leftSideUpIteration.Y -= DistanceToIterateBy; } if (favorDown || favorNeither) { if (IsGood(leftSideDownIteration, rightSideDownIteration)) { return(new BorderNodeGeometry(rightSideDownIteration, BorderNodeDocking.Right)); } if (!IsInBounds(leftSideDownIteration, rightSideDownIteration)) { favorDown = false; } rightSideDownIteration.Y += DistanceToIterateBy; leftSideDownIteration.Y += DistanceToIterateBy; } if (favorNeither && !IsInBounds(leftSideUpIteration, rightSideUpIteration) && !IsInBounds(leftSideDownIteration, rightSideDownIteration)) { // Give up, neither is within bounds. break; } favorNeither = !favorUp && !favorDown; } return(new BorderNodeGeometry(rightBounds, BorderNodeDocking.Right)); }