fix(ui): consolidate mainwindow corner/clip fixes

This commit is contained in:
Meik
2026-03-05 17:25:56 +01:00
parent a7fc42b876
commit 97f87b9dcd
4 changed files with 213 additions and 36 deletions

View File

@@ -10,12 +10,14 @@ using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shell;
@@ -74,8 +76,18 @@ namespace C4IT_CustomerPanel
private TimeSpan _lastAdHocInterval;
private TimeSpan _lastRegularInterval;
private bool _allowApplicationShutdown = false;
private bool _mainSurfaceClipInitialized = false;
internal DateTime lastUpdate;
[DllImport("gdi32.dll")]
private static extern IntPtr CreateRoundRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect, int nWidthEllipse, int nHeightEllipse);
[DllImport("user32.dll")]
private static extern int SetWindowRgn(IntPtr hWnd, IntPtr hRgn, bool bRedraw);
[DllImport("gdi32.dll")]
private static extern bool DeleteObject(IntPtr hObject);
//private Dictionary<announcementType, List<Guid>> announcementIDCollection = new Dictionary<announcementType, List<Guid>>();
public bool _userIsAuthenticated = false;
public enumOnlineState OnlineState = enumOnlineState.Initializing;
@@ -144,6 +156,7 @@ namespace C4IT_CustomerPanel
FormHelper.GetLocation((int)this.Width, (int)this.Height, (double)ConfigSettings.local_currentDPI / 96);
SetAppearance(true);
UpdateMainSurfaceClip();
SetLocation();
CustomerPanelSecurePassword.Init();
@@ -231,6 +244,16 @@ namespace C4IT_CustomerPanel
private void Window_Loaded(object sender, RoutedEventArgs e)
{
ComputerInfoCtrl.FillMainInfoGrid();
UpdateMainSurfaceClip();
ApplyRoundedWindowRegion();
if (!_mainSurfaceClipInitialized)
{
Dispatcher.BeginInvoke(new Action(UpdateMainSurfaceClip), DispatcherPriority.Loaded);
Dispatcher.BeginInvoke(new Action(UpdateMainSurfaceClip), DispatcherPriority.Render);
Dispatcher.BeginInvoke(new Action(ApplyRoundedWindowRegion), DispatcherPriority.Loaded);
Dispatcher.BeginInvoke(new Action(ApplyRoundedWindowRegion), DispatcherPriority.Render);
}
NetworkChange.NetworkAddressChanged += new NetworkAddressChangedEventHandler(AddressChangedCallback);
}
@@ -2157,9 +2180,139 @@ namespace C4IT_CustomerPanel
private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{
UpdateMainSurfaceClip();
ApplyRoundedWindowRegion();
SetLocation();
}
private void UpdateMainSurfaceClip()
{
if (MainWindowSurface == null || MainWindowContentRoot == null || MainGrid == null)
return;
double surfaceWidth = MainWindowSurface.ActualWidth;
double surfaceHeight = MainWindowSurface.ActualHeight;
double contentWidth = MainWindowContentRoot.ActualWidth;
double contentHeight = MainWindowContentRoot.ActualHeight;
if (surfaceWidth <= 0 || surfaceHeight <= 0 || contentWidth <= 0 || contentHeight <= 0)
return;
const double surfaceRadius = 20d;
const double contentRadius = 19d;
MainGrid.Clip = null;
this.Clip = null;
MainWindowSurface.Clip = new RectangleGeometry(new Rect(0d, 0d, surfaceWidth, surfaceHeight), surfaceRadius, surfaceRadius);
MainWindowContentRoot.Clip = new RectangleGeometry(new Rect(0d, 0d, contentWidth, contentHeight), contentRadius, contentRadius);
if (MainWindowCornerMaskOverlay != null)
{
MainWindowCornerMaskOverlay.Data = CreateCornerOverflowMaskGeometry(surfaceWidth, surfaceHeight, surfaceRadius);
}
if (MainWindowFrameOverlay != null)
{
MainWindowFrameOverlay.Data = CreateFrameOverlayGeometry(surfaceWidth, surfaceHeight, surfaceRadius, 1d);
}
if (btnSP != null && btnSP.ActualWidth > 0d && btnSP.ActualHeight > 0d)
{
btnSP.Clip = CreateBottomRoundedRectGeometry(btnSP.ActualWidth, btnSP.ActualHeight, contentRadius);
}
_mainSurfaceClipInitialized = true;
}
private static Geometry CreateBottomRoundedRectGeometry(double width, double height, double radius)
{
if (width <= 0d || height <= 0d)
return Geometry.Empty;
double r = Math.Max(0d, Math.Min(radius, Math.Min(width / 2d, height / 2d)));
if (r <= 0d)
return new RectangleGeometry(new Rect(0d, 0d, width, height));
var geometry = new StreamGeometry();
using (var context = geometry.Open())
{
context.BeginFigure(new System.Windows.Point(0d, 0d), true, true);
context.LineTo(new System.Windows.Point(width, 0d), true, false);
context.LineTo(new System.Windows.Point(width, height - r), true, false);
context.ArcTo(new System.Windows.Point(width - r, height), new System.Windows.Size(r, r), 0d, false, SweepDirection.Clockwise, true, false);
context.LineTo(new System.Windows.Point(r, height), true, false);
context.ArcTo(new System.Windows.Point(0d, height - r), new System.Windows.Size(r, r), 0d, false, SweepDirection.Clockwise, true, false);
context.LineTo(new System.Windows.Point(0d, 0d), true, false);
}
geometry.Freeze();
return geometry;
}
private static Geometry CreateCornerOverflowMaskGeometry(double width, double height, double radius)
{
if (width <= 0d || height <= 0d)
return Geometry.Empty;
double r = Math.Max(0d, Math.Min(radius, Math.Min(width / 2d, height / 2d)));
if (r <= 0d)
return Geometry.Empty;
var fullRect = new RectangleGeometry(new Rect(0d, 0d, width, height));
var roundedRect = new RectangleGeometry(new Rect(0d, 0d, width, height), r, r);
var mask = new CombinedGeometry(GeometryCombineMode.Exclude, fullRect, roundedRect);
mask.Freeze();
return mask;
}
private static Geometry CreateFrameOverlayGeometry(double width, double height, double radius, double strokeThickness)
{
if (width <= 0d || height <= 0d)
return Geometry.Empty;
double inset = Math.Max(0d, strokeThickness / 2d);
double frameWidth = Math.Max(0d, width - strokeThickness);
double frameHeight = Math.Max(0d, height - strokeThickness);
if (frameWidth <= 0d || frameHeight <= 0d)
return Geometry.Empty;
double frameRadius = Math.Max(0d, Math.Min(radius - inset, Math.Min(frameWidth / 2d, frameHeight / 2d)));
var frame = new RectangleGeometry(new Rect(inset, inset, frameWidth, frameHeight), frameRadius, frameRadius);
frame.Freeze();
return frame;
}
private void ApplyRoundedWindowRegion()
{
if (!IsLoaded || WindowState == WindowState.Minimized)
return;
IntPtr hwnd = new WindowInteropHelper(this).Handle;
if (hwnd == IntPtr.Zero)
return;
PresentationSource source = PresentationSource.FromVisual(this);
if (source?.CompositionTarget == null)
return;
Matrix toDevice = source.CompositionTarget.TransformToDevice;
int pxWidth = Math.Max(1, (int)Math.Ceiling(ActualWidth * toDevice.M11));
int pxHeight = Math.Max(1, (int)Math.Ceiling(ActualHeight * toDevice.M22));
const double radiusDip = 20d;
int ellipseWidth = Math.Max(2, (int)Math.Ceiling(radiusDip * 2d * toDevice.M11));
int ellipseHeight = Math.Max(2, (int)Math.Ceiling(radiusDip * 2d * toDevice.M22));
IntPtr hRgn = CreateRoundRectRgn(0, 0, pxWidth + 1, pxHeight + 1, ellipseWidth, ellipseHeight);
if (hRgn == IntPtr.Zero)
return;
if (SetWindowRgn(hwnd, hRgn, true) == 0)
{
DeleteObject(hRgn);
}
}
}
public class cMainFunctionInfo