csharpc-sharpdotnetxamlavaloniauicross-platformcross-platform-xamlavaloniaguimulti-platformuser-interfacedotnetcore
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
147 lines
5.5 KiB
147 lines
5.5 KiB
using System;
|
|
using Avalonia.Controls;
|
|
using Avalonia.Input;
|
|
using static Avalonia.Win32.Interop.UnmanagedMethods;
|
|
|
|
#nullable enable
|
|
|
|
namespace Avalonia.Win32
|
|
{
|
|
public partial class WindowImpl
|
|
{
|
|
// Hit test the frame for resizing and moving.
|
|
private HitTestValues HitTestNCA(IntPtr hWnd, IntPtr wParam, IntPtr lParam)
|
|
{
|
|
// Get the point coordinates for the hit test (screen space).
|
|
var ptMouse = PointFromLParam(lParam);
|
|
|
|
// Get the window rectangle.
|
|
GetWindowRect(hWnd, out var rcWindow);
|
|
|
|
// Get the frame rectangle, adjusted for the style without a caption.
|
|
var rcFrame = new RECT();
|
|
AdjustWindowRectEx(ref rcFrame, (uint)(WindowStyles.WS_OVERLAPPEDWINDOW & ~WindowStyles.WS_CAPTION), false, 0);
|
|
|
|
var borderThickness = new RECT();
|
|
if (GetStyle().HasFlag(WindowStyles.WS_THICKFRAME))
|
|
{
|
|
AdjustWindowRectEx(ref borderThickness, (uint)(GetStyle()), false, 0);
|
|
borderThickness.left *= -1;
|
|
borderThickness.top *= -1;
|
|
}
|
|
else if (GetStyle().HasFlag(WindowStyles.WS_BORDER))
|
|
{
|
|
borderThickness = new RECT { bottom = 1, left = 1, right = 1, top = 1 };
|
|
}
|
|
|
|
if (_extendTitleBarHint >= 0)
|
|
{
|
|
borderThickness.top = (int)(_extendedMargins.Top * RenderScaling);
|
|
}
|
|
|
|
// Determine if the hit test is for resizing. Default middle (1,1).
|
|
ushort uRow = 1;
|
|
ushort uCol = 1;
|
|
bool onResizeBorder = false;
|
|
|
|
// Determine if the point is at the left or right of the window.
|
|
if (ptMouse.X >= rcWindow.left && ptMouse.X < rcWindow.left + borderThickness.left)
|
|
{
|
|
uCol = 0; // left side
|
|
}
|
|
else if (ptMouse.X < rcWindow.right && ptMouse.X >= rcWindow.right - borderThickness.right)
|
|
{
|
|
uCol = 2; // right side
|
|
}
|
|
|
|
// Determine if the point is at the top or bottom of the window.
|
|
if (ptMouse.Y >= rcWindow.top && ptMouse.Y < rcWindow.top + borderThickness.top)
|
|
{
|
|
onResizeBorder = (ptMouse.Y < (rcWindow.top - rcFrame.top));
|
|
|
|
// Two cases where we have a valid row 0 hit test:
|
|
// - window resize border (top resize border hit)
|
|
// - area below resize border that is actual titlebar (caption hit).
|
|
if (onResizeBorder || uCol == 1)
|
|
{
|
|
uRow = 0;
|
|
}
|
|
}
|
|
else if (ptMouse.Y < rcWindow.bottom && ptMouse.Y >= rcWindow.bottom - borderThickness.bottom)
|
|
{
|
|
uRow = 2;
|
|
}
|
|
|
|
ReadOnlySpan<HitTestValues> hitZones = stackalloc HitTestValues[]
|
|
{
|
|
HitTestValues.HTTOPLEFT, onResizeBorder ? HitTestValues.HTTOP : HitTestValues.HTCAPTION,
|
|
HitTestValues.HTTOPRIGHT, HitTestValues.HTLEFT, HitTestValues.HTNOWHERE, HitTestValues.HTRIGHT,
|
|
HitTestValues.HTBOTTOMLEFT, HitTestValues.HTBOTTOM, HitTestValues.HTBOTTOMRIGHT
|
|
};
|
|
|
|
var zoneIndex = uRow * 3 + uCol;
|
|
|
|
return hitZones[zoneIndex];
|
|
}
|
|
|
|
protected virtual IntPtr CustomCaptionProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam, ref bool callDwp)
|
|
{
|
|
IntPtr lRet = IntPtr.Zero;
|
|
|
|
callDwp = !DwmDefWindowProc(hWnd, msg, wParam, lParam, ref lRet);
|
|
|
|
switch ((WindowsMessage)msg)
|
|
{
|
|
case WindowsMessage.WM_DWMCOMPOSITIONCHANGED:
|
|
// TODO handle composition changed.
|
|
break;
|
|
|
|
case WindowsMessage.WM_NCHITTEST:
|
|
if (lRet == IntPtr.Zero)
|
|
{
|
|
if(WindowState == WindowState.FullScreen)
|
|
{
|
|
return (IntPtr)HitTestValues.HTCLIENT;
|
|
}
|
|
var hittestResult = HitTestNCA(hWnd, wParam, lParam);
|
|
|
|
lRet = (IntPtr)hittestResult;
|
|
|
|
uint timestamp = unchecked((uint)GetMessageTime());
|
|
|
|
if (hittestResult == HitTestValues.HTCAPTION)
|
|
{
|
|
var position = PointToClient(PointFromLParam(lParam));
|
|
|
|
if (_owner is Window window)
|
|
{
|
|
var visual = window.Renderer.HitTestFirst(position, _owner as Window, x =>
|
|
{
|
|
if (x is IInputElement ie && !ie.IsHitTestVisible)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
});
|
|
|
|
if (visual != null)
|
|
{
|
|
hittestResult = HitTestValues.HTCLIENT;
|
|
lRet = (IntPtr)hittestResult;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hittestResult != HitTestValues.HTNOWHERE)
|
|
{
|
|
callDwp = false;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return lRet;
|
|
}
|
|
}
|
|
}
|
|
|