using System; using System.Drawing; using System.Runtime.InteropServices; using System.Windows.Forms; namespace Pingerino.Utilities { public static class UIHelper { // Windows API constants and imports for form dragging public const int WM_NCLBUTTONDOWN = 0xA1; public const int HT_CAPTION = 0x2; [DllImport("user32.dll")] public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam); [DllImport("user32.dll")] public static extern bool ReleaseCapture(); [DllImport("Gdi32.dll", EntryPoint = "CreateRoundRectRgn")] public static extern IntPtr CreateRoundRectRgn( int nLeftRect, int nTopRect, int nRightRect, int nBottomRect, int nWidthEllipse, int nHeightEllipse); /// /// Enables form dragging by mouse /// public static void EnableFormDragging(Form form, Control dragControl) { dragControl.MouseDown += (sender, e) => { if (e.Button == MouseButtons.Left) { ReleaseCapture(); SendMessage(form.Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0); } }; } /// /// Applies rounded corners to a form /// public static void ApplyRoundedCorners(Form form, int radius = 30) { form.Region = Region.FromHrgn(CreateRoundRectRgn(0, 0, form.Width, form.Height, radius, radius)); } /// /// Safely updates UI control from any thread /// public static void SafeInvoke(Control control, Action action) { if (control == null || control.IsDisposed) return; if (control.InvokeRequired) { try { control.Invoke(action); } catch (ObjectDisposedException) { // Control was disposed while trying to invoke } catch (InvalidOperationException) { // Control handle was not created or is being destroyed } } else { action(); } } /// /// Safely updates UI control from any thread with return value /// public static T SafeInvoke(Control control, Func func) { if (control == null || control.IsDisposed) return default(T); if (control.InvokeRequired) { try { return (T)control.Invoke(func); } catch (ObjectDisposedException) { return default(T); } catch (InvalidOperationException) { return default(T); } } else { return func(); } } /// /// Shows an error message with consistent styling /// public static void ShowError(string message, string title = "Error") { MessageBox.Show(message, title, MessageBoxButtons.OK, MessageBoxIcon.Error); } /// /// Shows an information message with consistent styling /// public static void ShowInformation(string message, string title = "Information") { MessageBox.Show(message, title, MessageBoxButtons.OK, MessageBoxIcon.Information); } /// /// Shows a confirmation dialog /// public static bool ShowConfirmation(string message, string title = "Confirm") { return MessageBox.Show(message, title, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes; } /// /// Formats time span for display /// public static string FormatTimeSpan(TimeSpan timeSpan) { if (timeSpan.TotalDays >= 1) return $"{timeSpan.Days}d {timeSpan.Hours}h {timeSpan.Minutes}m"; if (timeSpan.TotalHours >= 1) return $"{timeSpan.Hours}h {timeSpan.Minutes}m {timeSpan.Seconds}s"; if (timeSpan.TotalMinutes >= 1) return $"{timeSpan.Minutes}m {timeSpan.Seconds}s"; return $"{timeSpan.Seconds}.{timeSpan.Milliseconds:000}s"; } /// /// Formats bytes for display /// public static string FormatBytes(long bytes) { string[] suffixes = { "B", "KB", "MB", "GB", "TB" }; int counter = 0; decimal number = bytes; while (Math.Round(number / 1024) >= 1) { number /= 1024; counter++; } return $"{number:n1} {suffixes[counter]}"; } } }