/// <summary>
        /// Precalculates and caches line segments that the form can snap onto.
        /// </summary>
        private SnapGrid PrepareSizeMove(Control.ControlCollection mdiChildren)
        {
            // Ignore the possibility that the MDI client rectangle is empty.
            // Create a list of MDI child rectangles sorted by their z-order. (MDI child on top has index 0.)
            List <Rectangle> mdiChildRectangles = new List <Rectangle>();
            int mdiChildCount = mdiChildren.Count;

            for (int mdiChildIndex = 0; mdiChildIndex < mdiChildCount; ++mdiChildIndex)
            {
                if (mdiChildren[mdiChildIndex] is Form mdiChildForm && mdiChildForm.Visible && mdiChildForm.WindowState == FormWindowState.Normal)
                {
                    // Convert the bounds of this MDI child to screen coordinates.
                    Rectangle mdiChildRectangle = mdiChildForm.Bounds;
                    mdiChildRectangle.Offset(m_currentMdiClientScreenRectangle.Left, m_currentMdiClientScreenRectangle.Top);

                    if (Form != mdiChildForm)
                    {
                        // Intersect the MDI child rectangle with the MDI client rectangle, so the form does not snap to edges outside of the visible MDI client rectangle.
                        mdiChildRectangle = Rectangle.Intersect(mdiChildRectangle, m_currentMdiClientScreenRectangle);

                        // Only add non-empty rectangles.
                        if (mdiChildRectangle.Left < mdiChildRectangle.Right && mdiChildRectangle.Top < mdiChildRectangle.Bottom)
                        {
                            mdiChildRectangles.Add(mdiChildRectangle);
                        }
                    }
                    else
                    {
                        // Save original rectangle, so its properties can be used to keep positions or sizes constant during sizing and/or moving.
                        m_rectangleBeforeSizeMove = mdiChildRectangle;
                    }
                }
            }

            // Calculate snappable segments and save them to arrays which can be used efficiently from within the event handlers.
            List <LineSegment> verticalSegments   = SnapGrid.GetVerticalEdges(ref m_currentMdiClientScreenRectangle, 0);
            List <LineSegment> horizontalSegments = SnapGrid.GetHorizontalEdges(ref m_currentMdiClientScreenRectangle, 0);

            return(new SnapGrid(verticalSegments, horizontalSegments, mdiChildRectangles, InsensitiveBorderEndLength));
        }
        /// <summary>
        /// Checks if line segments that the form can snap onto should be precalculated (again).
        /// </summary>
        private void CheckUpdateSizeMove()
        {
            Form parentForm = Form.MdiParent;

            if (parentForm != null)
            {
                foreach (Control c in parentForm.Controls)
                {
                    if (c is MdiClient)
                    {
                        // Get the bounds of the MDI client relative to the screen coordinates, because that is also how the size/move rectangles will be passed into WndProc().
                        Rectangle currentMdiClientScreenRectangle = c.RectangleToScreen(c.ClientRectangle);
                        if (m_snapGrid == null || currentMdiClientScreenRectangle != m_currentMdiClientScreenRectangle)
                        {
                            m_currentMdiClientScreenRectangle = currentMdiClientScreenRectangle;
                            m_snapGrid = PrepareSizeMove(c.Controls);
                        }

                        // No need to check 'other' MdiClients, so stop looping.
                        return;
                    }
                }
            }
        }
        private void OwnedForm_ResizeBegin(object sender, EventArgs e)
        {
            // Precalculate size/move line segments.
            Form parentForm = Form.Owner;

            if (parentForm != null)
            {
                m_rectangleBeforeSizeMove = Form.Bounds;

                // Enumerate all siblings and the parent form in z-order.
                Form[]      snapTargetForms = parentForm.OwnedForms.Union(new SingleElementEnumerable <Form>(parentForm)).ToArray();
                IntPtr[]    handles         = snapTargetForms.Where(x => x.IsHandleCreated).Select(x => x.Handle).ToArray();
                int         handleCount     = handles.Length;
                List <Form> formsInZOrder   = new List <Form>(handleCount);

                NativeMethods.EnumWindows(
                    new EnumThreadWindowsCallback((handle, lParam) =>
                {
                    int handleIndex = Array.IndexOf(handles, handle);
                    if (handleIndex >= 0)
                    {
                        formsInZOrder.Add(snapTargetForms[handleIndex]);
                        handles[handleIndex] = IntPtr.Zero;
                        handleCount--;
                    }
                    return(handleCount > 0);
                }), IntPtr.Zero);

                // Now build the snap grid from all working areas edges, then the sibling rectangles.
                var verticalSegments   = new List <LineSegment>();
                var horizontalSegments = new List <LineSegment>();

                foreach (Screen screen in Screen.AllScreens)
                {
                    Rectangle workingArea = screen.WorkingArea;
                    verticalSegments.AddRange(SnapGrid.GetVerticalEdges(ref workingArea, InsensitiveBorderEndLength));
                    horizontalSegments.AddRange(SnapGrid.GetHorizontalEdges(ref workingArea, InsensitiveBorderEndLength));
                }

                // Add snap line segments for each sibling.
                List <Rectangle> siblingRectangles = new List <Rectangle>();
                foreach (Form form in formsInZOrder)
                {
                    if (form != Form && form.Visible && form.WindowState == FormWindowState.Normal)
                    {
                        Rectangle bounds = form.Bounds;

                        // Only add non-empty rectangles.
                        if (bounds.Left < bounds.Right && bounds.Top < bounds.Bottom)
                        {
                            siblingRectangles.Add(bounds);
                        }
                    }
                }

                m_snapGrid = new SnapGrid(verticalSegments, horizontalSegments, siblingRectangles, InsensitiveBorderEndLength);

                if (SnapWhileMoving)
                {
                    Form.Moving += OwnedForm_Moving;
                }
                if (SnapWhileResizing)
                {
                    Form.Resizing += OwnedForm_Resizing;
                }
            }
        }
 private void OwnedForm_ResizeEnd(object sender, EventArgs e)
 {
     Form.Moving   -= OwnedForm_Moving;
     Form.Resizing -= OwnedForm_Resizing;
     m_snapGrid     = null;
 }
 private void MdiChild_ResizeEnd(object sender, EventArgs e)
 {
     Form.Moving   -= MdiChild_Moving;
     Form.Resizing -= MdiChild_Resizing;
     m_snapGrid     = null;
 }