From 116750ec58e608138b9fd17195b4f8fe287630c4 Mon Sep 17 00:00:00 2001 From: krjan02 Date: Mon, 13 Jan 2025 23:24:22 +0100 Subject: [PATCH] Added dynamic icon (displays battery state) --- SoraV2Utils_Agent/DynamicIcon.cs | 67 ++++++++++++++++++++++ SoraV2Utils_Agent/TrayIconForm.cs | 94 +++++++++++++++++++++++++++++++ 2 files changed, 161 insertions(+) create mode 100644 SoraV2Utils_Agent/DynamicIcon.cs create mode 100644 SoraV2Utils_Agent/TrayIconForm.cs diff --git a/SoraV2Utils_Agent/DynamicIcon.cs b/SoraV2Utils_Agent/DynamicIcon.cs new file mode 100644 index 0000000..0d9377b --- /dev/null +++ b/SoraV2Utils_Agent/DynamicIcon.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Drawing.Imaging; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Drawing.Text; + +namespace SoraV2Utils_Agent +{ + internal class DynamicIcon + { + public static Icon CreateIcon(string text, Color textColor, Font font) + { + if (string.IsNullOrEmpty(text) || text.Length > 3) + throw new ArgumentException("Text must be between 1 and 3 characters long.", nameof(text)); + + // Create a 32x32 transparent bitmap + using (Bitmap bitmap = new Bitmap(32, 32)) + { + using (Graphics g = Graphics.FromImage(bitmap)) + { + // Set up transparency + g.Clear(Color.Transparent); + + // Enable anti-aliasing for smoother text + g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; + + // Determine the largest font size that will fit within 32x32 + float maxFontSize = 48; // Start with a large font size + SizeF textSize; + Font adjustedFont; + do + { + maxFontSize--; + adjustedFont = new Font(font.FontFamily, maxFontSize, font.Style); + textSize = g.MeasureString(text, adjustedFont); + } + while ((textSize.Width > 42 || textSize.Height > 42) && maxFontSize > 1); + + if (textSize.Width > 42 || textSize.Height > 42) + { + // Reduce back if the scaled size exceeds 32x32 + maxFontSize /= 1.25f; + adjustedFont = new Font(font.FontFamily, maxFontSize, font.Style); + textSize = g.MeasureString(text, adjustedFont); + } + + // Calculate the position to center the text + float x = (32 - textSize.Width) / 2; + float y = (32 - textSize.Height) / 2; + + // Draw the text + using (SolidBrush textBrush = new SolidBrush(textColor)) + { + g.DrawString(text, adjustedFont, textBrush, x, y); + } + } + + // Create and return the icon + return Icon.FromHandle(bitmap.GetHicon()); + } + } + } +} diff --git a/SoraV2Utils_Agent/TrayIconForm.cs b/SoraV2Utils_Agent/TrayIconForm.cs new file mode 100644 index 0000000..5209272 --- /dev/null +++ b/SoraV2Utils_Agent/TrayIconForm.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using System.Drawing; +using System.Threading; + +namespace SoraV2Utils_Agent +{ + public class TrayIconForm + { + public TrayIconForm() + { + // Create a NotifyIcon instance + using (NotifyIcon trayIcon = new NotifyIcon()) + { + // Set up the tray icon properties + trayIcon.Icon = new Icon(DynamicIcon.CreateIcon("##",Color.Red, SystemFonts.IconTitleFont), 40, 40); // Choose your own icon + trayIcon.Visible = true; + + // Create a context menu + var contextMenu = new ContextMenu(); + + // Add a non-clickable dynamic text item + var batteryLevelItem = new MenuItem("Battery Level: Loading..."); + var batteryRuntimeItem = new MenuItem("Battery Runtime: Loading..."); + batteryLevelItem.Enabled = false; + batteryRuntimeItem.Enabled = false; + + contextMenu.MenuItems.Add("Exit", (sender, e) => ServiceIPC.Instance.Exit()); + contextMenu.MenuItems.Add("Check for Update ", (sender, e) => UpdateCheck.CheckUpdate()); + + contextMenu.MenuItems.Add(batteryLevelItem); + contextMenu.MenuItems.Add(batteryRuntimeItem); + + trayIcon.ContextMenu = contextMenu; + + // Update the dynamic text in the context menu + ThreadPool.QueueUserWorkItem(state => + { + while (true) + { + // Format battery level with charging status + string batteryLevelText = ServiceIPC.DeviceStatus.Charging == 1 + ? $"Battery Level: {ServiceIPC.DeviceStatus.Battery} (Charging...)" + : $"Battery Level: {ServiceIPC.DeviceStatus.Battery}"; + + // Format battery runtime (convert minutes to hours and minutes) + string batteryRuntimeText = FormatBatteryRuntime(ServiceIPC.BatteryRuntime); + + // Update the context menu items + batteryLevelItem.Text = batteryLevelText; + batteryRuntimeItem.Text = $"Battery Runtime: {batteryRuntimeText}"; + batteryRuntimeItem.Text = $"Battery Runtime: {batteryRuntimeText}"; + trayIcon.Icon = new Icon(DynamicIcon.CreateIcon(ServiceIPC.DeviceStatus.Battery.ToString(), Color.White, new Font("Arial",32)), 32, 32); + + // Update every second + Thread.Sleep(1000); + } + }); + + Application.Run(); + } + } + + // Formats the runtime in hours and minutes. + private string FormatBatteryRuntime(double runtimeInMinutes) + { + if(runtimeInMinutes < 0) + { + return "No data yet"; + } + + int hours = (int)(runtimeInMinutes / 60); + int minutes = (int)(runtimeInMinutes % 60); + + // If runtime is greater than 1 hour, display hours and minutes + if (hours > 0) + { + return $"{hours} hour{(hours > 1 ? "s" : "")} {minutes} minute{(minutes > 1 ? "s" : "")}"; + } + else + { + return $"{minutes} minute{(minutes > 1 ? "s" : "")}"; + } + } + + public void Display() + { + } + } +}