From 4dbc0aabc780b846b24bf25600d45a953d78855e Mon Sep 17 00:00:00 2001 From: Jonathan Jenne Date: Thu, 23 Sep 2021 11:04:31 +0200 Subject: [PATCH] Windows/Window: Add SnapToBorder --- Windows/Window.vb | 87 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/Windows/Window.vb b/Windows/Window.vb index 08932317..1d390fb2 100644 --- a/Windows/Window.vb +++ b/Windows/Window.vb @@ -7,6 +7,8 @@ Imports DigitalData.Modules.Logging Public Class Window Private _Logger As Logger + Private Const WINDOW_SNAP_OFFSET = 35 + Public Enum Anchor TopLeft BottomLeft @@ -387,4 +389,89 @@ Public Class Window Throw ex End Try End Function + + + Public Structure WINDOWPOS + Public hwnd As IntPtr + Public hwndInsertAfter As IntPtr + Public x As Integer + Public y As Integer + Public cx As Integer + Public cy As Integer + Public flags As Integer + End Structure + + Public Shared Sub SnapToDesktopBorder(pForm As Form, pLParam As IntPtr, Optional pWidthAdjustment As Integer = 0) + If pForm Is Nothing Then + ' Satisfies rule: Validate parameters + Throw New ArgumentNullException("pForm") + End If + + ' Snap client to the top, left, bottom or right desktop border + ' as the form is moved near that border + Try + ' Marshal the LPARAM value which is a WINDOWPOS struct + Dim oNewPosition As New WINDOWPOS + oNewPosition = CType(Marshal.PtrToStructure(pLParam, GetType(WINDOWPOS)), WINDOWPOS) + + If oNewPosition.y = 0 OrElse oNewPosition.x = 0 Then + Return ' Nothing to do! + End If + + ' Adjust the client size for borders and caption bar + Dim oClientRect As Rectangle = pForm.RectangleToScreen(pForm.ClientRectangle) + oClientRect.Width += SystemInformation.FrameBorderSize.Width - pWidthAdjustment + oClientRect.Height += (SystemInformation.FrameBorderSize.Height + SystemInformation.CaptionHeight) + + ' Now get the screen working area (without taskbar) + Dim oWorkingRect As Rectangle = System.Windows.Forms.Screen.GetWorkingArea(pForm.ClientRectangle) + + ' Left border + If oNewPosition.x >= oWorkingRect.X - WINDOW_SNAP_OFFSET AndAlso + oNewPosition.x <= oWorkingRect.X + WINDOW_SNAP_OFFSET Then + oNewPosition.x = oWorkingRect.X + End If + + ' Get screen bounds and taskbar height + ' (when taskbar is horizontal) + Dim oScreenRect As Rectangle = System.Windows.Forms.Screen.GetBounds(System.Windows.Forms.Screen.PrimaryScreen.Bounds) + Dim oTaskbarHeight As Integer = oScreenRect.Height - oWorkingRect.Height + + ' Top border (check if taskbar is on top + ' or bottom via WorkingRect.Y) + If oNewPosition.y >= -WINDOW_SNAP_OFFSET AndAlso + (oWorkingRect.Y > 0 AndAlso oNewPosition.y <= + (oTaskbarHeight + WINDOW_SNAP_OFFSET)) OrElse + (oWorkingRect.Y <= 0 AndAlso oNewPosition.y <= + (WINDOW_SNAP_OFFSET)) Then + If oTaskbarHeight > 0 Then + oNewPosition.y = oWorkingRect.Y ' Horizontal Taskbar + Else + oNewPosition.y = 0 ' Vertical Taskbar + End If + End If + + ' Right border + If oNewPosition.x + oClientRect.Width <= + oWorkingRect.Right + WINDOW_SNAP_OFFSET AndAlso + oNewPosition.x + oClientRect.Width >= + oWorkingRect.Right - WINDOW_SNAP_OFFSET Then + oNewPosition.x = oWorkingRect.Right - (oClientRect.Width + + SystemInformation.FrameBorderSize.Width) + End If + + ' Bottom border + If oNewPosition.y + oClientRect.Height <= + oWorkingRect.Bottom + WINDOW_SNAP_OFFSET AndAlso + oNewPosition.y + oClientRect.Height >= + oWorkingRect.Bottom - WINDOW_SNAP_OFFSET Then + oNewPosition.y = oWorkingRect.Bottom - (oClientRect.Height + + SystemInformation.FrameBorderSize.Height) + End If + + ' Marshal it back + Marshal.StructureToPtr(oNewPosition, pLParam, True) + Catch ex As ArgumentException + End Try + End Sub End Class