elfisa-pharmacy/src/Elfisa.UI/Helpers/WindowChromeHelper.cs

158 lines
5.6 KiB
C#

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Elfisa.UI.Theming;
namespace Elfisa.UI.Helpers
{
public static class WindowChromeHelper
{
private const int DwmwaUseImmersiveDarkMode = 20;
private const int DwmwaUseImmersiveDarkModeLegacy = 19;
private const int DwmwaCaptionColor = 35;
private const int DwmwaTextColor = 36;
private const uint SwpNomove = 0x0002;
private const uint SwpNosize = 0x0001;
private const uint SwpNozorder = 0x0004;
private const uint SwpFramechanged = 0x0020;
[DllImport("dwmapi.dll", PreserveSig = true)]
private static extern int DwmSetWindowAttribute(IntPtr hwnd, int dwAttribute, ref int pvAttribute, int cbAttribute);
[DllImport("dwmapi.dll", PreserveSig = true)]
private static extern int DwmSetWindowAttribute(IntPtr hwnd, int dwAttribute, ref uint pvAttribute, int cbAttribute);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool SetWindowPos(
IntPtr hWnd,
IntPtr hWndInsertAfter,
int x,
int y,
int cx,
int cy,
uint uFlags);
public static void ApplyTitleBarTheme(Form form, ThemeColors theme)
{
if (form == null || theme == null || !form.IsHandleCreated)
{
return;
}
var isDark = theme.Mode == ThemeMode.Dark;
var useDarkMode = isDark ? 1 : 0;
TrySetInt(form.Handle, DwmwaUseImmersiveDarkMode, useDarkMode);
TrySetInt(form.Handle, DwmwaUseImmersiveDarkModeLegacy, useDarkMode);
var caption = theme.AccentPrimary;
var text = IsLightCaption(caption) ? Color.Black : Color.White;
TrySetUInt(form.Handle, DwmwaCaptionColor, ColorToDwm(caption));
TrySetUInt(form.Handle, DwmwaTextColor, ColorToDwm(text));
RefreshNonClientArea(form);
}
/// <summary>
/// Обработка ресайза для FormBorderStyle.None (края окна).
/// </summary>
public static bool TryHandleNcHitTest(Form form, ref Message m, int border = 6)
{
const int wmNcHitTest = 0x84;
if (m.Msg != wmNcHitTest || form == null)
{
return false;
}
var screen = new Point(m.LParam.ToInt32() & 0xFFFF, (m.LParam.ToInt32() >> 16) & 0xFFFF);
// signed short for multi-monitor negative coords
screen = new Point((short)(m.LParam.ToInt32() & 0xFFFF), (short)((m.LParam.ToInt32() >> 16) & 0xFFFF));
var client = form.PointToClient(screen);
var w = form.ClientSize.Width;
var h = form.ClientSize.Height;
var left = client.X <= border;
var right = client.X >= w - border;
var top = client.Y <= border;
var bottom = client.Y >= h - border;
if (top && left) { m.Result = (IntPtr)13; return true; } // HTTOPLEFT
if (top && right) { m.Result = (IntPtr)14; return true; } // HTTOPRIGHT
if (bottom && left) { m.Result = (IntPtr)16; return true; } // HTBOTTOMLEFT
if (bottom && right) { m.Result = (IntPtr)17; return true; } // HTBOTTOMRIGHT
if (left) { m.Result = (IntPtr)10; return true; } // HTLEFT
if (right) { m.Result = (IntPtr)11; return true; } // HTRIGHT
if (top) { m.Result = (IntPtr)12; return true; } // HTTOP
if (bottom) { m.Result = (IntPtr)15; return true; } // HTBOTTOM
return false;
}
public static void ApplyThemedDialogHeader(Panel headerPanel, Label headerLabel, ThemeColors theme)
{
if (theme == null)
{
return;
}
if (headerPanel != null)
{
headerPanel.BackColor = theme.TitleBarTop;
}
if (headerLabel != null)
{
headerLabel.ForeColor = IsLightCaption(theme.TitleBarTop) ? Color.Black : Color.White;
}
}
private static bool IsLightCaption(Color color)
{
var luminance = (0.299 * color.R) + (0.587 * color.G) + (0.114 * color.B);
return luminance > 180;
}
public static void ApplyDialogChrome(Form form, Panel headerPanel = null, Label headerLabel = null)
{
if (form == null)
{
return;
}
var theme = ThemeManager.Colors;
ApplyThemedDialogHeader(headerPanel, headerLabel, theme);
if (form.IsHandleCreated)
{
ApplyTitleBarTheme(form, theme);
}
else
{
form.HandleCreated += (_, __) => ApplyTitleBarTheme(form, ThemeManager.Colors);
}
}
private static uint ColorToDwm(Color color)
{
return (uint)(color.R | (color.G << 8) | (color.B << 16));
}
private static void RefreshNonClientArea(Form form)
{
SetWindowPos(form.Handle, IntPtr.Zero, 0, 0, 0, 0, SwpNomove | SwpNosize | SwpNozorder | SwpFramechanged);
}
private static void TrySetInt(IntPtr handle, int attribute, int value)
{
DwmSetWindowAttribute(handle, attribute, ref value, sizeof(int));
}
private static void TrySetUInt(IntPtr handle, int attribute, uint value)
{
DwmSetWindowAttribute(handle, attribute, ref value, sizeof(uint));
}
}
}