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); } /// /// Обработка ресайза для FormBorderStyle.None (края окна). /// 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)); } } }