Skip to content

Commit e8860dd

Browse files
committed
Add SnapLayoutManager #131
1 parent 7caf7ee commit e8860dd

File tree

2 files changed

+111
-1
lines changed

2 files changed

+111
-1
lines changed
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
namespace DevWinUI;
2+
3+
public partial class SnapLayoutManager
4+
{
5+
private const int HTMAXBUTTON = 9;
6+
7+
private Window window;
8+
private FrameworkElement snapElement;
9+
private WindowMessageMonitor monitor;
10+
11+
public bool IsEnabled { get; set; } = true;
12+
13+
public void Attach(Window window, FrameworkElement element)
14+
{
15+
Detach();
16+
17+
this.window = window;
18+
this.snapElement = element;
19+
20+
this.window.Closed += OnWindowClosed;
21+
22+
monitor = new WindowMessageMonitor(this.window);
23+
monitor.WindowMessageReceived += OnWindowMessageReceived;
24+
25+
window.ExtendsContentIntoTitleBar = true;
26+
}
27+
28+
private void OnWindowClosed(object sender, WindowEventArgs e)
29+
{
30+
Detach();
31+
}
32+
33+
public void Detach()
34+
{
35+
if (window != null)
36+
window.Closed -= OnWindowClosed;
37+
38+
if (monitor != null)
39+
{
40+
monitor.WindowMessageReceived -= OnWindowMessageReceived;
41+
(monitor as IDisposable)?.Dispose();
42+
}
43+
44+
monitor = null;
45+
window = null;
46+
snapElement = null;
47+
}
48+
49+
private void OnWindowMessageReceived(object? sender, WindowMessageEventArgs e)
50+
{
51+
if (!IsEnabled)
52+
return;
53+
54+
switch (e.MessageType)
55+
{
56+
case (uint)NativeValues.WindowMessage.WM_NCHITTEST:
57+
HandleNcHitTest(e);
58+
break;
59+
60+
case (uint)NativeValues.WindowMessage.WM_NCRBUTTONDOWN:
61+
e.Result = 0;
62+
e.Handled = true;
63+
break;
64+
}
65+
}
66+
67+
private void HandleNcHitTest(WindowMessageEventArgs e)
68+
{
69+
if (snapElement == null || window == null)
70+
return;
71+
72+
int x = (short)(e.Message.LParam.ToInt32() & 0xFFFF);
73+
int y = (short)(e.Message.LParam.ToInt32() >> 16);
74+
75+
var mouse = new Point(x, y);
76+
77+
Rect rect = GetButtonScreenRect(snapElement);
78+
if (rect == Rect.Empty)
79+
return;
80+
81+
if (rect.Contains(mouse))
82+
{
83+
e.Result = (nint)HTMAXBUTTON;
84+
e.Handled = true;
85+
}
86+
}
87+
88+
private Rect GetButtonScreenRect(FrameworkElement element)
89+
{
90+
if (element == null || window?.Content == null)
91+
return Rect.Empty;
92+
93+
var point = element.TransformToVisual(window.Content as UIElement)
94+
.TransformPoint(new Windows.Foundation.Point(0, 0));
95+
96+
double scale = element.XamlRoot.RasterizationScale;
97+
double left = point.X * scale;
98+
double top = point.Y * scale;
99+
double width = element.ActualWidth * scale;
100+
double height = element.ActualHeight * scale;
101+
102+
var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(window);
103+
var pt = new System.Drawing.Point((int)Math.Round(left), (int)Math.Round(top));
104+
Windows.Win32.PInvoke.ClientToScreen(new(hwnd), ref pt);
105+
106+
return new Rect(pt.X, pt.Y, width, height);
107+
}
108+
}
109+

dev/DevWinUI/NativeMethods.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
CombineRgn
1+
ClientToScreen
2+
CombineRgn
23
CoWaitForMultipleObjects
34
CreateEllipticRgn
45
CreateEvent

0 commit comments

Comments
 (0)