82 lines
2.9 KiB
C#
82 lines
2.9 KiB
C#
|
|
using System;
|
|
using System.Drawing;
|
|
using System.Runtime.InteropServices;
|
|
using System.Windows.Forms;
|
|
|
|
using static mpvnet.Native;
|
|
|
|
namespace mpvnet
|
|
{
|
|
public class SnapManager
|
|
{
|
|
int DragOffsetX { get; set; }
|
|
int DragOffsetY { get; set; }
|
|
|
|
IntPtr Handle;
|
|
|
|
[Flags]
|
|
public enum SnapLocation
|
|
{
|
|
None = 0,
|
|
Left = 1 << 0,
|
|
Top = 1 << 1,
|
|
Right = 1 << 2,
|
|
Bottom = 1 << 3,
|
|
All = Left | Top | Right | Bottom
|
|
}
|
|
|
|
public int AnchorDistance { get; set; }
|
|
|
|
public int SnapDistance { get; set; }
|
|
|
|
bool InSnapRange(int a, int b) => Math.Abs(a - b) < SnapDistance;
|
|
|
|
void FindSnap(ref Rectangle effectiveBounds)
|
|
{
|
|
Screen currentScreen = Screen.FromPoint(effectiveBounds.Location);
|
|
Rectangle workingArea = GetWorkingArea(Handle, currentScreen.WorkingArea);
|
|
|
|
if (InSnapRange(effectiveBounds.Left, workingArea.Left + AnchorDistance))
|
|
effectiveBounds.X = workingArea.Left + AnchorDistance;
|
|
else if (InSnapRange(effectiveBounds.Right, workingArea.Right - AnchorDistance))
|
|
effectiveBounds.X = workingArea.Right - AnchorDistance - effectiveBounds.Width;
|
|
if (InSnapRange(effectiveBounds.Top, workingArea.Top + AnchorDistance))
|
|
effectiveBounds.Y = workingArea.Top + AnchorDistance;
|
|
else if (InSnapRange(effectiveBounds.Bottom, workingArea.Bottom - AnchorDistance))
|
|
effectiveBounds.Y = workingArea.Bottom - AnchorDistance - effectiveBounds.Height;
|
|
}
|
|
|
|
public void OnMoving(ref Message m)
|
|
{
|
|
if (Handle == IntPtr.Zero)
|
|
return;
|
|
|
|
RECT boundsLtrb = Marshal.PtrToStructure<RECT>(m.LParam);
|
|
Rectangle bounds = boundsLtrb.ToRectangle();
|
|
// This is where the window _would_ be located if snapping
|
|
// had not occurred. This prevents the cursor from sliding
|
|
// off the title bar if the snap distance is too large.
|
|
Rectangle effectiveBounds = new Rectangle(
|
|
Cursor.Position.X - DragOffsetX,
|
|
Cursor.Position.Y - DragOffsetY,
|
|
bounds.Width,
|
|
bounds.Height);
|
|
FindSnap(ref effectiveBounds);
|
|
RECT newLtrb = RECT.FromRectangle(effectiveBounds);
|
|
Marshal.StructureToPtr(newLtrb, m.LParam, false);
|
|
m.Result = new IntPtr(1);
|
|
}
|
|
|
|
public void OnSizeAndEnterSizeMove(Form form)
|
|
{
|
|
Handle = form.Handle;
|
|
SnapDistance = form.Font.Height;
|
|
// Need to handle window size changed as well when
|
|
// un-maximizing the form by dragging the title bar.
|
|
DragOffsetX = Cursor.Position.X - form.Left;
|
|
DragOffsetY = Cursor.Position.Y - form.Top;
|
|
}
|
|
}
|
|
}
|