public MagnetEdge GetOppsiteEdge() { return(new MagnetEdge { EdgeDir = MagnetUtils.OppsiteEdge(EdgeDir), End = End, Start = Start, Window = null }); }
private int FindClosestEdge(MagnetEdge refEdge) { if (refEdge == null) { return(int.MinValue); } // get all forms edges list var edges = Forms .Where(frm => (frm != m_OriginalForm) && frm.Visible) .SelectMany(MagnetUtils.FormToEdges) .Where(t => !m_MoveLocks.Any(q => (q.Item1 == t.Window) && (q.Item2 == MagnetUtils.OppsiteEdge(t.EdgeDir)))) .ToList(); var corners = Forms .Where(frm => (frm != m_OriginalForm) && frm.Visible) .SelectMany(MagnetUtils.FormToCorners) .Where(t => !m_ResizeLocks.Any(q => (q.Item1 == t.Window) && (q.Item2 == t.AttractsEdge))) .ToList(); var bestDist = int.MaxValue; foreach (var edge in edges) { var dist = edge.MeasureAttraction(refEdge); if (dist != int.MinValue) { if (Math.Abs(dist) < bestDist) { bestDist = dist; } } } foreach (var corner in corners) { var dist = corner.MeasureAttraction(refEdge); if (dist != int.MinValue) { if (Math.Abs(dist) < bestDist) { bestDist = dist; } } } return(bestDist); }
protected override void WndProc(ref Message m) { if (m.Msg == WM_ENTERSIZEMOVE) { // Reset move tracking var currRect = new WinRect(); GetWindowRect(Handle, ref currRect); m_MoveSum = new Point(currRect.Left, currRect.Top); m_MovePrevPos = new Point(currRect.Left, currRect.Top); // Scan for move locks m_MoveLocks.Clear(); var otherEdges = Forms .Where(frm => (frm != m_OriginalForm) && frm.Visible) .Where(frm => Forms.IndexOf(m_OriginalForm) == 0) .SelectMany(MagnetUtils.FormToEdges).ToList(); var windowEdges = MagnetUtils.RectToEdges(currRect.ToRectangle()); foreach (var windowEdge in windowEdges) { foreach (var otherEdge in otherEdges) { if (windowEdge.MeasureAttraction(otherEdge) == 0) { m_MoveLocks.Add(new Tuple <Form, EdgeDirection>(otherEdge.Window, windowEdge.EdgeDir)); } } } // Scan for resize locks m_ResizeLocks.Clear(); foreach (var windowEdge in windowEdges) { foreach (var otherEdge in otherEdges) { if ((windowEdge.EdgeDir == otherEdge.EdgeDir) && ((windowEdge.Start == otherEdge.End) || (windowEdge.End == otherEdge.Start))) { m_ResizeLocks.Add(new Tuple <Form, EdgeDirection>(otherEdge.Window, otherEdge.EdgeDir)); } } } // Remove resize locks duplications m_ResizeLocks = m_ResizeLocks.GroupBy(a => a.Item1.GetHashCode() ^ a.Item2.GetHashCode()).Select(grp => grp.First()).ToList(); } else if (m.Msg == WM_SIZING) { var rc = (WinRect)Marshal.PtrToStructure(m.LParam, typeof(WinRect)); // Convert WinRect into edge list var resizeRect = rc.ToRectangle(); var windowEdges = MagnetUtils.RectToEdges(resizeRect).ToDictionary(edge => edge.EdgeDir, edge => edge); // Create resize map var map = new Dictionary <int, EdgeDirection[]> { { WMSZ_LEFT, new[] { EdgeDirection.Left } }, { WMSZ_RIGHT, new[] { EdgeDirection.Right } }, { WMSZ_TOP, new[] { EdgeDirection.Top } }, { WMSZ_BOTTOM, new[] { EdgeDirection.Bottom } }, { WMSZ_LEFT + WMSZ_TOP, new[] { EdgeDirection.Left, EdgeDirection.Top } }, { WMSZ_LEFT + WMSZ_BOTTOM, new[] { EdgeDirection.Left, EdgeDirection.Bottom } }, { WMSZ_RIGHT + WMSZ_TOP, new[] { EdgeDirection.Right, EdgeDirection.Top } }, { WMSZ_RIGHT + WMSZ_BOTTOM, new[] { EdgeDirection.Right, EdgeDirection.Bottom } }, }; // Edge list EdgeDirection[] edgeList; if (!map.TryGetValue(m.WParam.ToInt32(), out edgeList)) { edgeList = new EdgeDirection[0]; } // Handle horizontal resize foreach (var edgeDir in edgeList) { var movingEdge = windowEdges[edgeDir]; var magDistance = FindClosestEdge(movingEdge); if (Math.Abs(magDistance) < 20) { resizeRect = MagnetUtils.ShiftRectangleEdge(resizeRect, edgeDir, magDistance); } } // Rebuild new position edges windowEdges = MagnetUtils.RectToEdges(resizeRect).ToDictionary(a => a.EdgeDir, a => a); // Enforce resize locks foreach (var resizeLock in m_ResizeLocks) { var otherRect = resizeLock.Item1.Bounds; otherRect = MagnetUtils.SetRectangleEdge(otherRect, windowEdges[resizeLock.Item2]); resizeLock.Item1.SetBounds(otherRect.X, otherRect.Y, otherRect.Width, otherRect.Height); } // Enfore move-on-resize windows foreach (var moveLock in m_MoveLocks) { var otherRect = moveLock.Item1.Bounds; otherRect = MagnetUtils.SetEntireRectangleEdge(otherRect, windowEdges[moveLock.Item2].GetOppsiteEdge()); moveLock.Item1.SetBounds(otherRect.X, otherRect.Y, otherRect.Width, otherRect.Height); } // Convert rect to LParam rc = WinRect.FromRectangle(resizeRect); Marshal.StructureToPtr(rc, m.LParam, true); m.Result = new IntPtr(1); } else if (m.Msg == WM_MOVING) { var rc = (WinRect)Marshal.PtrToStructure(m.LParam, typeof(WinRect)); // Update MoveSum m_MoveSum.X += rc.Left - m_MovePrevPos.X; m_MoveSum.Y += rc.Top - m_MovePrevPos.Y; // Convert WinRect into edge list var moveRect = rc.ToRectangle(); moveRect.Location = m_MoveSum; // Do magnetics twice, this has to be done so edge-to-edge works first and only then edge-to-corner works for (int i = 0; i < 2; i++) { // Scan all edges directions and check if we can stick to other windows foreach (EdgeDirection edgeType in Enum.GetValues(typeof(EdgeDirection))) { // Get edge info var edge = MagnetUtils.RectToEdges(moveRect).First(t => t.EdgeDir == edgeType); // Stick to other windows var magDistance = FindClosestEdge(edge); if (Math.Abs(magDistance) < 20) { moveRect = MagnetUtils.ShiftEntireRectangle(moveRect, edge.EdgeDir, magDistance); } } } // Move other windows foreach (var lockedWindows in m_MoveLocks) { var otherRect = lockedWindows.Item1.Bounds; otherRect.Offset(moveRect.Location.X - m_MovePrevPos.X, moveRect.Location.Y - m_MovePrevPos.Y); lockedWindows.Item1.SetBounds(otherRect.X, otherRect.Y, otherRect.Width, otherRect.Height); } // Save position to track delta m_MovePrevPos = moveRect.Location; // Convert rect to LParam rc = WinRect.FromRectangle(moveRect); Marshal.StructureToPtr(rc, m.LParam, true); m.Result = new IntPtr(1); } base.WndProc(ref m); }