From 21b6ad3d7530206be8d219bbe136f287ad05d85f Mon Sep 17 00:00:00 2001 From: NinjaPug <36635276+programmingPug@users.noreply.github.com> Date: Mon, 14 Apr 2025 12:46:10 -0400 Subject: [PATCH] restructure --- .../ConfiguratorForm.Designer.cs | 257 ------- PCPalConfigurator/ConfiguratorForm.cs | 721 ------------------ PCPalConfigurator/{ => Core}/ConfigData.cs | 5 +- PCPalConfigurator/Core/MarkupParser.cs | 189 +++++ PCPalConfigurator/Core/SensorManager.cs | 237 ++++++ PCPalConfigurator/PCPalConfigurator.csproj | 6 - .../PCPalConfigurator.csproj.user | 7 +- PCPalConfigurator/Program.cs | 9 +- .../Rendering/Elements/BarElement.cs | 30 + .../Rendering/Elements/IconElement.cs | 24 + .../Rendering/Elements/LineElement.cs | 20 + .../Rendering/Elements/RectElement.cs | 30 + .../Rendering/Elements/TextElement.cs | 31 + PCPalConfigurator/Rendering/PreviewElement.cs | 15 + PCPalConfigurator/Rendering/RenderPreview.cs | 64 ++ .../UI/ConfiguratorForm.Designer.cs | 256 +++++++ PCPalConfigurator/UI/ConfiguratorForm.cs | 292 +++++++ .../{ => UI}/ConfiguratorForm.resx | 0 .../IconBrowser.Designer.cs | 5 +- .../{IconBrowser => UI}/IconBrowser.cs | 5 +- .../{IconBrowser => UI}/IconBrowser.resx | 0 PCPalConfigurator/UI/OledPreviewPanel.cs | 44 ++ 22 files changed, 1257 insertions(+), 990 deletions(-) delete mode 100644 PCPalConfigurator/ConfiguratorForm.Designer.cs delete mode 100644 PCPalConfigurator/ConfiguratorForm.cs rename PCPalConfigurator/{ => Core}/ConfigData.cs (84%) create mode 100644 PCPalConfigurator/Core/MarkupParser.cs create mode 100644 PCPalConfigurator/Core/SensorManager.cs create mode 100644 PCPalConfigurator/Rendering/Elements/BarElement.cs create mode 100644 PCPalConfigurator/Rendering/Elements/IconElement.cs create mode 100644 PCPalConfigurator/Rendering/Elements/LineElement.cs create mode 100644 PCPalConfigurator/Rendering/Elements/RectElement.cs create mode 100644 PCPalConfigurator/Rendering/Elements/TextElement.cs create mode 100644 PCPalConfigurator/Rendering/PreviewElement.cs create mode 100644 PCPalConfigurator/Rendering/RenderPreview.cs create mode 100644 PCPalConfigurator/UI/ConfiguratorForm.Designer.cs create mode 100644 PCPalConfigurator/UI/ConfiguratorForm.cs rename PCPalConfigurator/{ => UI}/ConfiguratorForm.resx (100%) rename PCPalConfigurator/{IconBrowser => UI}/IconBrowser.Designer.cs (99%) rename PCPalConfigurator/{IconBrowser => UI}/IconBrowser.cs (98%) rename PCPalConfigurator/{IconBrowser => UI}/IconBrowser.resx (100%) create mode 100644 PCPalConfigurator/UI/OledPreviewPanel.cs diff --git a/PCPalConfigurator/ConfiguratorForm.Designer.cs b/PCPalConfigurator/ConfiguratorForm.Designer.cs deleted file mode 100644 index b6319f6..0000000 --- a/PCPalConfigurator/ConfiguratorForm.Designer.cs +++ /dev/null @@ -1,257 +0,0 @@ -namespace PCPalConfigurator -{ - partial class ConfiguratorForm - { - private System.ComponentModel.IContainer components = null; - - private TabControl tabControl; - private TabPage tab1602; - private TabPage tabTFT; - private TabPage tabOLED; - private TabPage tabHelp; - private TabPage tabAbout; - - private ComboBox cmbLine1; - private TextBox txtLine1; - private TextBox txtLine1Post; - private ComboBox cmbLine2; - private TextBox txtLine2; - private TextBox txtLine2Post; - private Button btnSave; - - private Label lblLine1; - private Label lblLine1Prefix; - private Label lblLine1Suffix; - private Label lblLine2; - private Label lblLine2Prefix; - private Label lblLine2Suffix; - - // OLED tab controls - private TextBox txtOledMarkup; - private Panel panelOledButtons; - private Button btnInsertIcon; - private Button btnLoadOledExample; - private Button btnSaveOled; - private Panel panelOledPreview; - private Button btnPreview; - private Label lblPreviewHeader; - - // Help tab controls - private TextBox txtHelpContent; - - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - components.Dispose(); - - base.Dispose(disposing); - } - - private void InitializeComponent() - { - this.tabControl = new TabControl(); - this.tab1602 = new TabPage("1602 LCD"); - this.tabTFT = new TabPage("4.6\" TFT LCD"); - this.tabOLED = new TabPage("OLED Display"); - this.tabHelp = new TabPage("Help"); - this.tabAbout = new TabPage("About"); - - this.cmbLine1 = new ComboBox(); - this.txtLine1 = new TextBox(); - this.txtLine1Post = new TextBox(); - this.cmbLine2 = new ComboBox(); - this.txtLine2 = new TextBox(); - this.txtLine2Post = new TextBox(); - this.btnSave = new Button(); - - this.lblLine1 = new Label(); - this.lblLine1Prefix = new Label(); - this.lblLine1Suffix = new Label(); - this.lblLine2 = new Label(); - this.lblLine2Prefix = new Label(); - this.lblLine2Suffix = new Label(); - - // OLED tab controls - this.txtOledMarkup = new TextBox(); - this.panelOledButtons = new Panel(); - this.btnInsertIcon = new Button(); - this.btnLoadOledExample = new Button(); - this.btnSaveOled = new Button(); - this.panelOledPreview = new Panel(); - this.btnPreview = new Button(); - this.lblPreviewHeader = new Label(); - - // Help tab controls - this.txtHelpContent = new TextBox(); - - // === TabControl === - this.tabControl.Dock = DockStyle.Fill; - this.tabControl.TabPages.Add(this.tab1602); - this.tabControl.TabPages.Add(this.tabTFT); - this.tabControl.TabPages.Add(this.tabOLED); - this.tabControl.TabPages.Add(this.tabHelp); - this.tabControl.TabPages.Add(this.tabAbout); - this.Controls.Add(this.tabControl); - - // === Line 1 UI === - this.lblLine1.Text = "Line 1:"; - this.lblLine1.Location = new System.Drawing.Point(20, 20); - this.lblLine1.AutoSize = true; - - this.cmbLine1.Location = new System.Drawing.Point(100, 18); - this.cmbLine1.Size = new System.Drawing.Size(200, 21); - - this.lblLine1Prefix.Text = "Prefix:"; - this.lblLine1Prefix.Location = new System.Drawing.Point(20, 50); - this.lblLine1Prefix.AutoSize = true; - - this.txtLine1.Location = new System.Drawing.Point(100, 48); - this.txtLine1.Size = new System.Drawing.Size(200, 21); - - this.lblLine1Suffix.Text = "Suffix / Units:"; - this.lblLine1Suffix.Location = new System.Drawing.Point(320, 50); - this.lblLine1Suffix.AutoSize = true; - - this.txtLine1Post.Location = new System.Drawing.Point(420, 48); - this.txtLine1Post.Size = new System.Drawing.Size(120, 21); - - // === Line 2 UI === - this.lblLine2.Text = "Line 2:"; - this.lblLine2.Location = new System.Drawing.Point(20, 90); - this.lblLine2.AutoSize = true; - - this.cmbLine2.Location = new System.Drawing.Point(100, 88); - this.cmbLine2.Size = new System.Drawing.Size(200, 21); - - this.lblLine2Prefix.Text = "Prefix:"; - this.lblLine2Prefix.Location = new System.Drawing.Point(20, 120); - this.lblLine2Prefix.AutoSize = true; - - this.txtLine2.Location = new System.Drawing.Point(100, 118); - this.txtLine2.Size = new System.Drawing.Size(200, 21); - - this.lblLine2Suffix.Text = "Suffix / Units:"; - this.lblLine2Suffix.Location = new System.Drawing.Point(320, 120); - this.lblLine2Suffix.AutoSize = true; - - this.txtLine2Post.Location = new System.Drawing.Point(420, 118); - this.txtLine2Post.Size = new System.Drawing.Size(120, 21); - - // === Save Button (renamed from Apply) === - this.btnSave.Text = "Save"; - this.btnSave.Location = new System.Drawing.Point(20, 170); - this.btnSave.Size = new System.Drawing.Size(100, 30); - this.btnSave.Click += new System.EventHandler(this.btnSave_Click); - - // === Add to 1602 Tab === - this.tab1602.Controls.AddRange(new Control[] - { - lblLine1, cmbLine1, lblLine1Prefix, txtLine1, lblLine1Suffix, txtLine1Post, - lblLine2, cmbLine2, lblLine2Prefix, txtLine2, lblLine2Suffix, txtLine2Post, - btnSave - }); - - // === OLED Tab Setup === - // Main panel for layout - Panel oledMainPanel = new Panel(); - oledMainPanel.Dock = DockStyle.Fill; - this.tabOLED.Controls.Add(oledMainPanel); - - // Markup editor - this.txtOledMarkup = new TextBox(); - this.txtOledMarkup.Multiline = true; - this.txtOledMarkup.ScrollBars = ScrollBars.Vertical; - this.txtOledMarkup.Font = new Font("Consolas", 9.75F); - this.txtOledMarkup.TextChanged += new EventHandler(this.txtOledMarkup_TextChanged); - this.txtOledMarkup.Size = new Size(580, 130); - this.txtOledMarkup.Location = new Point(10, 10); - oledMainPanel.Controls.Add(this.txtOledMarkup); - - // Button panel - this.panelOledButtons = new Panel(); - this.panelOledButtons.Size = new Size(580, 40); - this.panelOledButtons.Location = new Point(10, 150); - oledMainPanel.Controls.Add(this.panelOledButtons); - - this.btnInsertIcon = new Button(); - this.btnInsertIcon.Text = "Insert Icon"; - this.btnInsertIcon.Location = new Point(0, 7); - this.btnInsertIcon.Size = new Size(120, 26); - this.btnInsertIcon.Click += new EventHandler(this.btnInsertIcon_Click); - this.panelOledButtons.Controls.Add(this.btnInsertIcon); - - this.btnLoadOledExample = new Button(); - this.btnLoadOledExample.Text = "Load Example"; - this.btnLoadOledExample.Location = new Point(130, 7); - this.btnLoadOledExample.Size = new Size(120, 26); - this.btnLoadOledExample.Click += new EventHandler(this.btnLoadOledExample_Click); - this.panelOledButtons.Controls.Add(this.btnLoadOledExample); - - this.btnPreview = new Button(); - this.btnPreview.Text = "Update Preview"; - this.btnPreview.Location = new Point(260, 7); - this.btnPreview.Size = new Size(120, 26); - this.btnPreview.Click += new EventHandler(this.btnPreview_Click); - this.panelOledButtons.Controls.Add(this.btnPreview); - - this.btnSaveOled = new Button(); - this.btnSaveOled.Text = "Save"; - this.btnSaveOled.Location = new Point(480, 7); - this.btnSaveOled.Size = new Size(100, 26); - this.btnSaveOled.Click += new EventHandler(this.btnSave_Click); // Uses same event handler - this.panelOledButtons.Controls.Add(this.btnSaveOled); - - // Preview header - this.lblPreviewHeader = new Label(); - this.lblPreviewHeader.Text = "OLED Preview (256x64)"; - this.lblPreviewHeader.Location = new Point(10, 195); - this.lblPreviewHeader.Size = new Size(580, 20); - this.lblPreviewHeader.TextAlign = ContentAlignment.MiddleCenter; - this.lblPreviewHeader.BackColor = System.Drawing.SystemColors.ControlLight; - this.lblPreviewHeader.BorderStyle = BorderStyle.FixedSingle; - oledMainPanel.Controls.Add(this.lblPreviewHeader); - - // Preview panel - this.panelOledPreview = new Panel(); - this.panelOledPreview.Location = new Point(10, 215); - this.panelOledPreview.Size = new Size(580, 110); - this.panelOledPreview.BackColor = System.Drawing.Color.Black; - this.panelOledPreview.BorderStyle = BorderStyle.FixedSingle; - this.panelOledPreview.Paint += new PaintEventHandler(this.panelOledPreview_Paint); - oledMainPanel.Controls.Add(this.panelOledPreview); - - // === Help Tab Setup === - this.txtHelpContent = new TextBox(); - this.txtHelpContent.Dock = DockStyle.Fill; - this.txtHelpContent.Multiline = true; - this.txtHelpContent.ReadOnly = true; - this.txtHelpContent.ScrollBars = ScrollBars.Vertical; - this.txtHelpContent.Font = new Font("Segoe UI", 9F); - this.tabHelp.Controls.Add(this.txtHelpContent); - - // === TFT Tab Placeholder === - Label lblTFT = new Label() - { - Text = "TFT configuration coming soon...", - Location = new System.Drawing.Point(20, 20), - AutoSize = true - }; - this.tabTFT.Controls.Add(lblTFT); - - // === About Tab === - Label lblAbout = new Label() - { - Text = "PCPal Display Configurator\nFor ThermalTake Tower XXX\nVersion 1.0.0\n© 2025 Christopher Koch aka NinjaPug", - Location = new System.Drawing.Point(20, 20), - AutoSize = true - }; - this.tabAbout.Controls.Add(lblAbout); - - // === Form === - this.Text = "Display Configurator"; - this.ClientSize = new System.Drawing.Size(600, 380); // Adjusted size for compact layout - this.ResumeLayout(false); - this.PerformLayout(); - } - } -} \ No newline at end of file diff --git a/PCPalConfigurator/ConfiguratorForm.cs b/PCPalConfigurator/ConfiguratorForm.cs deleted file mode 100644 index 0e65267..0000000 --- a/PCPalConfigurator/ConfiguratorForm.cs +++ /dev/null @@ -1,721 +0,0 @@ -using System; -using System.IO; -using System.Text; -using System.Drawing; -using System.Windows.Forms; -using System.Collections.Generic; -using System.Text.RegularExpressions; -using Newtonsoft.Json; -using LibreHardwareMonitor.Hardware; - -namespace PCPalConfigurator -{ - public partial class ConfiguratorForm : Form - { - private ConfigData config; - private readonly string ConfigFile = GetConfigPath(); - private Computer computer; - private System.Windows.Forms.Timer sensorUpdateTimer; - - // Preview rendering data - private List previewElements = new List(); - private Dictionary sensorValues = new Dictionary(); - private bool autoUpdatePreview = true; - private const int OledWidth = 256; - private const int OledHeight = 64; - - // Classes for preview rendering - private abstract class PreviewElement - { - public abstract void Draw(Graphics g); - } - - private class TextElement : PreviewElement - { - public int X { get; set; } - public int Y { get; set; } - public int Size { get; set; } - public string Text { get; set; } - - public override void Draw(Graphics g) - { - // Choose font size based on the size parameter - Font font; - switch (Size) - { - case 1: font = new Font("Consolas", 8); break; - case 2: font = new Font("Consolas", 10); break; - case 3: font = new Font("Consolas", 12); break; - default: font = new Font("Consolas", 8); break; - } - - // Draw text with white color - g.DrawString(Text, font, Brushes.White, X, Y - font.Height); - } - } - - private class BarElement : PreviewElement - { - public int X { get; set; } - public int Y { get; set; } - public int Width { get; set; } - public int Height { get; set; } - public int Value { get; set; } - - public override void Draw(Graphics g) - { - // Draw outline rectangle - g.DrawRectangle(Pens.White, X, Y, Width, Height); - - // Calculate fill width based on value (0-100) - int fillWidth = (int)(Width * (Value / 100.0)); - if (fillWidth > 0) - { - // Draw filled portion - g.FillRectangle(Brushes.White, X + 1, Y + 1, fillWidth - 1, Height - 2); - } - } - } - - private class RectElement : PreviewElement - { - public int X { get; set; } - public int Y { get; set; } - public int Width { get; set; } - public int Height { get; set; } - public bool Filled { get; set; } - - public override void Draw(Graphics g) - { - if (Filled) - { - // Draw filled box - g.FillRectangle(Brushes.White, X, Y, Width, Height); - } - else - { - // Draw outline rectangle - g.DrawRectangle(Pens.White, X, Y, Width, Height); - } - } - } - - private class LineElement : PreviewElement - { - public int X1 { get; set; } - public int Y1 { get; set; } - public int X2 { get; set; } - public int Y2 { get; set; } - - public override void Draw(Graphics g) - { - g.DrawLine(Pens.White, X1, Y1, X2, Y2); - } - } - - private class IconElement : PreviewElement - { - public int X { get; set; } - public int Y { get; set; } - public string Name { get; set; } - - public override void Draw(Graphics g) - { - // For preview, just draw a placeholder rectangle with icon name - g.DrawRectangle(Pens.Gray, X, Y, 24, 24); - using (Font font = new Font("Arial", 6)) - { - g.DrawString(Name, font, Brushes.White, X + 2, Y + 8); - } - } - } - - public ConfiguratorForm() - { - InitializeComponent(); - InitHardware(); - InitSensorTimer(); - LoadConfig(); - PopulateHelpContent(); - UpdatePreview(); // Initial preview rendering - } - - private void InitHardware() - { - computer = new Computer - { - IsCpuEnabled = true, - IsGpuEnabled = true, - IsMemoryEnabled = true, - IsMotherboardEnabled = true, - IsControllerEnabled = true, - IsStorageEnabled = true - }; - computer.Open(); - PopulateSensorOptions(); - UpdateSensorValues(); - } - - private void InitSensorTimer() - { - // Create a timer to regularly update sensor values for the preview - sensorUpdateTimer = new System.Windows.Forms.Timer(); - sensorUpdateTimer.Interval = 1000; // Update every second - sensorUpdateTimer.Tick += SensorUpdateTimer_Tick; - sensorUpdateTimer.Start(); - } - - private void SensorUpdateTimer_Tick(object sender, EventArgs e) - { - // Only update when the OLED tab is selected to save resources - if (tabControl.SelectedTab == tabOLED) - { - UpdateSensorValues(); - UpdatePreview(); - } - } - - private void UpdateSensorValues() - { - // Update all hardware readings - foreach (var hardware in computer.Hardware) - { - hardware.Update(); - - foreach (var sensor in hardware.Sensors) - { - if (sensor.Value.HasValue) - { - string sensorId = GetSensorVariableName(hardware.Name, sensor.Name); - sensorValues[sensorId] = sensor.Value.Value; - } - } - } - } - - private static string GetConfigPath() - { - string folder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "PCPal"); - Directory.CreateDirectory(folder); - return Path.Combine(folder, "config.json"); - } - - private void LoadConfig() - { - if (File.Exists(ConfigFile)) - { - string json = File.ReadAllText(ConfigFile); - config = JsonConvert.DeserializeObject(json) ?? new ConfigData(); - ApplyConfig(); - } - else - { - config = new ConfigData(); - } - } - - private void ApplyConfig() - { - // LCD settings - cmbLine1.SelectedItem = config.Line1Selection; - txtLine1.Text = config.Line1CustomText; - txtLine1Post.Text = config.Line1PostText; - cmbLine2.SelectedItem = config.Line2Selection; - txtLine2.Text = config.Line2CustomText; - txtLine2Post.Text = config.Line2PostText; - - // OLED settings - txtOledMarkup.Text = config.OledMarkup; - - // Select the appropriate tab based on screen type - if (config.ScreenType == "1602") - tabControl.SelectedTab = tab1602; - else if (config.ScreenType == "TFT4_6") - tabControl.SelectedTab = tabTFT; - else if (config.ScreenType == "OLED") - tabControl.SelectedTab = tabOLED; - } - - private void SaveConfig() - { - // Determine screen type based on selected tab - if (tabControl.SelectedTab == tab1602) - config.ScreenType = "1602"; - else if (tabControl.SelectedTab == tabTFT) - config.ScreenType = "TFT4_6"; - else if (tabControl.SelectedTab == tabOLED) - config.ScreenType = "OLED"; - - // Save LCD settings - config.Line1Selection = cmbLine1.SelectedItem?.ToString(); - config.Line1CustomText = txtLine1.Text; - config.Line1PostText = txtLine1Post.Text; - config.Line2Selection = cmbLine2.SelectedItem?.ToString(); - config.Line2CustomText = txtLine2.Text; - config.Line2PostText = txtLine2Post.Text; - - // Save OLED settings - config.OledMarkup = txtOledMarkup.Text; - - string json = JsonConvert.SerializeObject(config, Formatting.Indented); - File.WriteAllText(ConfigFile, json); - MessageBox.Show("Settings saved!"); - } - - // Renamed from btnApply_Click to btnSave_Click - private void btnSave_Click(object sender, EventArgs e) - { - SaveConfig(); - } - - private void PopulateSensorOptions() - { - cmbLine1.Items.Clear(); - cmbLine2.Items.Clear(); - - foreach (var hardware in computer.Hardware) - { - hardware.Update(); - foreach (var sensor in hardware.Sensors) - { - if (sensor.SensorType == SensorType.Load || - sensor.SensorType == SensorType.Temperature || - sensor.SensorType == SensorType.Data || - sensor.SensorType == SensorType.Fan) - { - string option = $"{hardware.HardwareType}: {sensor.Name} ({sensor.SensorType})"; - cmbLine1.Items.Add(option); - cmbLine2.Items.Add(option); - } - } - } - - cmbLine1.Items.Add("Custom Text"); - cmbLine2.Items.Add("Custom Text"); - } - - private void PopulateHelpContent() - { - // Create help content for both LCD and OLED displays - StringBuilder sb = new StringBuilder(); - - // General Information - sb.AppendLine("PCPal Display Configurator Help"); - sb.AppendLine("=============================="); - sb.AppendLine(); - - // LCD Display Help - sb.AppendLine("LCD DISPLAY CONFIGURATION"); - sb.AppendLine("------------------------"); - sb.AppendLine("1. Select a sensor for each line or choose 'Custom Text'"); - sb.AppendLine("2. Set prefix text to appear before the sensor value"); - sb.AppendLine("3. Set suffix/units to appear after the sensor value"); - sb.AppendLine("4. Click 'Save' to apply your settings"); - sb.AppendLine(); - - // OLED Display Help - sb.AppendLine("OLED MARKUP REFERENCE"); - sb.AppendLine("---------------------"); - sb.AppendLine("The OLED display accepts markup tags to create your layout."); - sb.AppendLine(); - sb.AppendLine("Text: Hello World"); - sb.AppendLine(" - x, y: position coordinates (0,0 is top-left)"); - sb.AppendLine(" - size: 1-3 (small to large)"); - sb.AppendLine(); - sb.AppendLine("Progress Bar: "); - sb.AppendLine(" - x, y: position"); - sb.AppendLine(" - w, h: width and height"); - sb.AppendLine(" - val: value 0-100"); - sb.AppendLine(); - sb.AppendLine("Icon: "); - sb.AppendLine(" - Inserts a bitmap icon from the SD card"); - sb.AppendLine(" - Use the 'Insert Icon' button to browse available icons"); - sb.AppendLine(); - sb.AppendLine("Rectangle (outline): "); - sb.AppendLine(); - sb.AppendLine("Filled Box: "); - sb.AppendLine(); - sb.AppendLine("Line: "); - sb.AppendLine(); - - // Sensor variables - sb.AppendLine("SENSOR VARIABLES"); - sb.AppendLine("----------------"); - sb.AppendLine("Use {SensorName} syntax to include sensor values."); - sb.AppendLine("Example: CPU: {CPU_Core_i7_Total_Load}%"); - - // Add available sensor variables with their current values - sb.AppendLine(); - sb.AppendLine("Available sensor variables:"); - - var sensors = new Dictionary>(); - - foreach (var hardware in computer.Hardware) - { - hardware.Update(); - foreach (var sensor in hardware.Sensors) - { - if (sensor.Value.HasValue && - (sensor.SensorType == SensorType.Load || - sensor.SensorType == SensorType.Temperature || - sensor.SensorType == SensorType.Clock || - sensor.SensorType == SensorType.Fan || - sensor.SensorType == SensorType.Power || - sensor.SensorType == SensorType.Data)) - { - string sensorId = GetSensorVariableName(hardware.Name, sensor.Name); - sensors[sensorId] = new Tuple( - sensor.Value.Value, - $"{hardware.Name} {sensor.Name}", - sensor.SensorType); - } - } - } - - // Group sensors by type for easier reading - var sensorGroups = sensors.GroupBy(s => s.Value.Item3); - foreach (var group in sensorGroups) - { - sb.AppendLine(); - sb.AppendLine($"-- {group.Key} Sensors --"); - - foreach (var sensor in group) - { - string unit = GetSensorUnit(group.Key); - string value = FormatSensorValue(sensor.Value.Item1, group.Key); - sb.AppendLine($"{{{sensor.Key}}} = {value}{unit} ({sensor.Value.Item2})"); - } - } - - txtHelpContent.Text = sb.ToString(); - } - - private string GetSensorUnit(SensorType sensorType) - { - return sensorType switch - { - SensorType.Temperature => "°C", - SensorType.Load => "%", - SensorType.Clock => "MHz", - SensorType.Power => "W", - SensorType.Fan => "RPM", - SensorType.Flow => "L/h", - SensorType.Control => "%", - SensorType.Level => "%", - _ => "" - }; - } - - private string FormatSensorValue(float value, SensorType sensorType) - { - // Format different sensor types appropriately - return sensorType switch - { - SensorType.Temperature => value.ToString("F1"), - SensorType.Clock => value.ToString("F0"), - SensorType.Load => value.ToString("F1"), - SensorType.Fan => value.ToString("F0"), - SensorType.Power => value.ToString("F1"), - SensorType.Data => (value > 1024) ? (value / 1024).ToString("F1") : value.ToString("F1"), - _ => value.ToString("F1") - }; - } - - private string GetSensorVariableName(string hardwareName, string sensorName) - { - // Create a simplified and safe variable name - string name = $"{hardwareName}_{sensorName}" - .Replace(" ", "_") - .Replace("%", "Percent") - .Replace("#", "Num") - .Replace("/", "_") - .Replace("\\", "_") - .Replace("(", "") - .Replace(")", "") - .Replace(",", ""); - - return name; - } - - private void btnInsertIcon_Click(object sender, EventArgs e) - { - using IconBrowser browser = new(); - if (browser.ShowDialog() == DialogResult.OK) - { - // Get the icon markup and insert it at the cursor position - string iconMarkup = browser.GetIconMarkup(); - if (!string.IsNullOrEmpty(iconMarkup)) - { - int selectionStart = txtOledMarkup.SelectionStart; - txtOledMarkup.Text = txtOledMarkup.Text.Insert(selectionStart, iconMarkup); - txtOledMarkup.SelectionStart = selectionStart + iconMarkup.Length; - txtOledMarkup.Focus(); - - // Update preview - if (autoUpdatePreview) - UpdatePreview(); - } - } - } - - private void btnLoadOledExample_Click(object sender, EventArgs e) - { - // Create an appropriate example based on the user's hardware - string exampleMarkup = ""; - string cpuLoad = FindFirstSensorOfType(HardwareType.Cpu, SensorType.Load); - string cpuTemp = FindFirstSensorOfType(HardwareType.Cpu, SensorType.Temperature); - string gpuLoad = FindFirstSensorOfType(HardwareType.GpuNvidia, SensorType.Load); - string gpuTemp = FindFirstSensorOfType(HardwareType.GpuNvidia, SensorType.Temperature); - string ramUsed = FindFirstSensorOfType(HardwareType.Memory, SensorType.Data); - - exampleMarkup = "System Monitor\n"; - - if (!string.IsNullOrEmpty(cpuLoad) && !string.IsNullOrEmpty(cpuTemp)) - { - exampleMarkup += $"CPU: {{{cpuLoad}}}% ({{{cpuTemp}}}°C)\n"; - exampleMarkup += $"\n"; - } - else if (!string.IsNullOrEmpty(cpuLoad)) - { - exampleMarkup += $"CPU: {{{cpuLoad}}}%\n"; - exampleMarkup += $"\n"; - } - - if (!string.IsNullOrEmpty(gpuLoad) && !string.IsNullOrEmpty(gpuTemp)) - { - exampleMarkup += $"GPU: {{{gpuLoad}}}% ({{{gpuTemp}}}°C)\n"; - exampleMarkup += $"\n"; - } - else if (!string.IsNullOrEmpty(gpuLoad)) - { - exampleMarkup += $"GPU: {{{gpuLoad}}}%\n"; - exampleMarkup += $"\n"; - } - - if (!string.IsNullOrEmpty(ramUsed)) - { - exampleMarkup += $"RAM: {{{ramUsed}}} GB\n"; - } - - txtOledMarkup.Text = exampleMarkup; - - // Update preview - if (autoUpdatePreview) - UpdatePreview(); - } - - private string FindFirstSensorOfType(HardwareType hardwareType, SensorType sensorType) - { - foreach (var hardware in computer.Hardware) - { - if (hardware.HardwareType == hardwareType) - { - foreach (var sensor in hardware.Sensors) - { - if (sensor.SensorType == sensorType && sensor.Value.HasValue) - { - return GetSensorVariableName(hardware.Name, sensor.Name); - } - } - } - } - return string.Empty; - } - - private void btnPreview_Click(object sender, EventArgs e) - { - UpdateSensorValues(); - UpdatePreview(); - } - - private void txtOledMarkup_TextChanged(object sender, EventArgs e) - { - // If auto-update is enabled, update the preview when the markup changes - if (autoUpdatePreview) - { - UpdatePreview(); - } - } - - private void UpdatePreview() - { - try - { - // Clear existing elements - previewElements.Clear(); - - // Parse the markup into preview elements - string markup = ProcessVariablesInMarkup(txtOledMarkup.Text); - ParseMarkup(markup); - - // Trigger repaint of the preview panel - if (panelOledPreview != null) - panelOledPreview.Invalidate(); - } - catch (Exception ex) - { - // Don't show errors during preview - just skip rendering - Console.WriteLine($"Preview error: {ex.Message}"); - } - } - - private string ProcessVariablesInMarkup(string markup) - { - if (string.IsNullOrEmpty(markup)) - return string.Empty; - - // Replace variables with actual values - foreach (var sensor in sensorValues) - { - // Look for {variable} syntax in the markup - string variablePattern = $"{{{sensor.Key}}}"; - - // Format value based on type (integers vs decimals) - string formattedValue; - if (Math.Abs(sensor.Value - Math.Round(sensor.Value)) < 0.01) - { - formattedValue = $"{sensor.Value:F0}"; - } - else - { - formattedValue = $"{sensor.Value:F1}"; - } - - markup = markup.Replace(variablePattern, formattedValue); - } - - return markup; - } - - private void ParseMarkup(string markup) - { - if (string.IsNullOrEmpty(markup)) - return; - - // Parse text elements - Hello - foreach (Match match in Regex.Matches(markup, @"([^<]*)")) - { - previewElements.Add(new TextElement - { - X = int.Parse(match.Groups[1].Value), - Y = int.Parse(match.Groups[2].Value), - Size = match.Groups[3].Success ? int.Parse(match.Groups[3].Value) : 1, - Text = match.Groups[4].Value - }); - } - - // Parse bar elements - - foreach (Match match in Regex.Matches(markup, @"")) - { - previewElements.Add(new BarElement - { - X = int.Parse(match.Groups[1].Value), - Y = int.Parse(match.Groups[2].Value), - Width = int.Parse(match.Groups[3].Value), - Height = int.Parse(match.Groups[4].Value), - Value = int.Parse(match.Groups[5].Value) - }); - } - - // Parse rect elements - - foreach (Match match in Regex.Matches(markup, @"")) - { - previewElements.Add(new RectElement - { - X = int.Parse(match.Groups[1].Value), - Y = int.Parse(match.Groups[2].Value), - Width = int.Parse(match.Groups[3].Value), - Height = int.Parse(match.Groups[4].Value), - Filled = false - }); - } - - // Parse box elements - - foreach (Match match in Regex.Matches(markup, @"")) - { - previewElements.Add(new RectElement - { - X = int.Parse(match.Groups[1].Value), - Y = int.Parse(match.Groups[2].Value), - Width = int.Parse(match.Groups[3].Value), - Height = int.Parse(match.Groups[4].Value), - Filled = true - }); - } - - // Parse line elements - - foreach (Match match in Regex.Matches(markup, @"")) - { - previewElements.Add(new LineElement - { - X1 = int.Parse(match.Groups[1].Value), - Y1 = int.Parse(match.Groups[2].Value), - X2 = int.Parse(match.Groups[3].Value), - Y2 = int.Parse(match.Groups[4].Value) - }); - } - - // Parse icon elements - - foreach (Match match in Regex.Matches(markup, @"")) - { - previewElements.Add(new IconElement - { - X = int.Parse(match.Groups[1].Value), - Y = int.Parse(match.Groups[2].Value), - Name = match.Groups[3].Value - }); - } - } - - private void panelOledPreview_Paint(object sender, PaintEventArgs e) - { - // Create graphics object with smooth rendering - e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; - - // Draw OLED display boundary - int panelWidth = panelOledPreview.Width; - int panelHeight = panelOledPreview.Height; - - // Calculate scale to fit preview in panel while maintaining aspect ratio - float scaleX = (float)panelWidth / OledWidth; - float scaleY = (float)panelHeight / OledHeight; - float scale = Math.Min(scaleX, scaleY); - - // Calculate centered position - int displayWidth = (int)(OledWidth * scale); - int displayHeight = (int)(OledHeight * scale); - int offsetX = (panelWidth - displayWidth) / 2; - int offsetY = (panelHeight - displayHeight) / 2; - - // Draw display outline - Rectangle displayRect = new Rectangle(offsetX, offsetY, displayWidth, displayHeight); - e.Graphics.DrawRectangle(Pens.DarkGray, displayRect); - - // Set up transformation to scale the preview elements - e.Graphics.TranslateTransform(offsetX, offsetY); - e.Graphics.ScaleTransform(scale, scale); - - // Draw all elements - foreach (var element in previewElements) - { - element.Draw(e.Graphics); - } - - // Reset transformation - e.Graphics.ResetTransform(); - - // Draw labels and guidelines - e.Graphics.DrawString($"OLED: {OledWidth}x{OledHeight}", new Font("Arial", 8), Brushes.Gray, 5, 5); - } - - protected override void OnFormClosing(FormClosingEventArgs e) - { - base.OnFormClosing(e); - - // Clean up resources - sensorUpdateTimer?.Stop(); - sensorUpdateTimer?.Dispose(); - computer?.Close(); - } - } -} \ No newline at end of file diff --git a/PCPalConfigurator/ConfigData.cs b/PCPalConfigurator/Core/ConfigData.cs similarity index 84% rename from PCPalConfigurator/ConfigData.cs rename to PCPalConfigurator/Core/ConfigData.cs index 5b9a2ed..8ee19bb 100644 --- a/PCPalConfigurator/ConfigData.cs +++ b/PCPalConfigurator/Core/ConfigData.cs @@ -1,5 +1,8 @@ -namespace PCPalConfigurator +namespace PCPalConfigurator.Core { + /// + /// Stores configuration data for PCPal displays + /// public class ConfigData { // Common settings diff --git a/PCPalConfigurator/Core/MarkupParser.cs b/PCPalConfigurator/Core/MarkupParser.cs new file mode 100644 index 0000000..757cd71 --- /dev/null +++ b/PCPalConfigurator/Core/MarkupParser.cs @@ -0,0 +1,189 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; +using LibreHardwareMonitor.Hardware; +using PCPalConfigurator.Rendering; +using PCPalConfigurator.Rendering.Elements; + +namespace PCPalConfigurator.Core +{ + /// + /// Parses OLED markup into renderable elements + /// + public class MarkupParser + { + private readonly Dictionary sensorValues; + + public MarkupParser(Dictionary sensorValues) + { + this.sensorValues = sensorValues ?? new Dictionary(); + } + + /// + /// Processes sensor variables in markup + /// + public string ProcessVariables(string markup) + { + if (string.IsNullOrEmpty(markup)) + return string.Empty; + + // Replace variables with actual values + foreach (var sensor in sensorValues) + { + // Look for {variable} syntax in the markup + string variablePattern = $"{{{sensor.Key}}}"; + + // Format value based on type (integers vs decimals) + string formattedValue; + if (Math.Abs(sensor.Value - Math.Round(sensor.Value)) < 0.01) + { + formattedValue = $"{sensor.Value:F0}"; + } + else + { + formattedValue = $"{sensor.Value:F1}"; + } + + markup = markup.Replace(variablePattern, formattedValue); + } + + return markup; + } + + /// + /// Parses markup and returns a list of preview elements + /// + public List ParseMarkup(string markup) + { + var elements = new List(); + + if (string.IsNullOrEmpty(markup)) + return elements; + + // Process variables in the markup first + markup = ProcessVariables(markup); + + // Parse text elements - Hello + foreach (Match match in Regex.Matches(markup, @"([^<]*)")) + { + elements.Add(new TextElement + { + X = int.Parse(match.Groups[1].Value), + Y = int.Parse(match.Groups[2].Value), + Size = match.Groups[3].Success ? int.Parse(match.Groups[3].Value) : 1, + Text = match.Groups[4].Value + }); + } + + // Parse bar elements - + foreach (Match match in Regex.Matches(markup, @"")) + { + elements.Add(new BarElement + { + X = int.Parse(match.Groups[1].Value), + Y = int.Parse(match.Groups[2].Value), + Width = int.Parse(match.Groups[3].Value), + Height = int.Parse(match.Groups[4].Value), + Value = int.Parse(match.Groups[5].Value) + }); + } + + // Parse rect elements - + foreach (Match match in Regex.Matches(markup, @"")) + { + elements.Add(new RectElement + { + X = int.Parse(match.Groups[1].Value), + Y = int.Parse(match.Groups[2].Value), + Width = int.Parse(match.Groups[3].Value), + Height = int.Parse(match.Groups[4].Value), + Filled = false + }); + } + + // Parse box elements - + foreach (Match match in Regex.Matches(markup, @"")) + { + elements.Add(new RectElement + { + X = int.Parse(match.Groups[1].Value), + Y = int.Parse(match.Groups[2].Value), + Width = int.Parse(match.Groups[3].Value), + Height = int.Parse(match.Groups[4].Value), + Filled = true + }); + } + + // Parse line elements - + foreach (Match match in Regex.Matches(markup, @"")) + { + elements.Add(new LineElement + { + X1 = int.Parse(match.Groups[1].Value), + Y1 = int.Parse(match.Groups[2].Value), + X2 = int.Parse(match.Groups[3].Value), + Y2 = int.Parse(match.Groups[4].Value) + }); + } + + // Parse icon elements - + foreach (Match match in Regex.Matches(markup, @"")) + { + elements.Add(new IconElement + { + X = int.Parse(match.Groups[1].Value), + Y = int.Parse(match.Groups[2].Value), + Name = match.Groups[3].Value + }); + } + + return elements; + } + + /// + /// Creates an example OLED markup using available sensors + /// + public static string CreateExampleMarkup(SensorManager sensorManager) + { + StringBuilder markup = new StringBuilder(); + + string cpuLoad = sensorManager.FindFirstSensorOfType(HardwareType.Cpu, SensorType.Load); + string cpuTemp = sensorManager.FindFirstSensorOfType(HardwareType.Cpu, SensorType.Temperature); + string gpuLoad = sensorManager.FindFirstSensorOfType(HardwareType.GpuNvidia, SensorType.Load); + string gpuTemp = sensorManager.FindFirstSensorOfType(HardwareType.GpuNvidia, SensorType.Temperature); + string ramUsed = sensorManager.FindFirstSensorOfType(HardwareType.Memory, SensorType.Data); + + markup.AppendLine("System Monitor"); + + if (!string.IsNullOrEmpty(cpuLoad) && !string.IsNullOrEmpty(cpuTemp)) + { + markup.AppendLine($"CPU: {{{cpuLoad}}}% ({{{cpuTemp}}}°C)"); + markup.AppendLine($""); + } + else if (!string.IsNullOrEmpty(cpuLoad)) + { + markup.AppendLine($"CPU: {{{cpuLoad}}}%"); + markup.AppendLine($""); + } + + if (!string.IsNullOrEmpty(gpuLoad) && !string.IsNullOrEmpty(gpuTemp)) + { + markup.AppendLine($"GPU: {{{gpuLoad}}}% ({{{gpuTemp}}}°C)"); + markup.AppendLine($""); + } + else if (!string.IsNullOrEmpty(gpuLoad)) + { + markup.AppendLine($"GPU: {{{gpuLoad}}}%"); + markup.AppendLine($""); + } + + if (!string.IsNullOrEmpty(ramUsed)) + { + markup.AppendLine($"RAM: {{{ramUsed}}} GB"); + } + + return markup.ToString(); + } + } +} \ No newline at end of file diff --git a/PCPalConfigurator/Core/SensorManager.cs b/PCPalConfigurator/Core/SensorManager.cs new file mode 100644 index 0000000..8669e41 --- /dev/null +++ b/PCPalConfigurator/Core/SensorManager.cs @@ -0,0 +1,237 @@ +using System; +using System.Collections.Generic; +using LibreHardwareMonitor.Hardware; + +namespace PCPalConfigurator.Core +{ + /// + /// Manages hardware sensors and provides access to sensor data + /// + public class SensorManager : IDisposable + { + private readonly Computer computer; + private readonly Dictionary sensorValues = new Dictionary(); + private bool isDisposed = false; + + public SensorManager() + { + computer = new Computer + { + IsCpuEnabled = true, + IsGpuEnabled = true, + IsMemoryEnabled = true, + IsMotherboardEnabled = true, + IsControllerEnabled = true, + IsStorageEnabled = true + }; + computer.Open(); + } + + /// + /// Updates all sensor values from hardware + /// + public void UpdateSensorValues() + { + foreach (var hardware in computer.Hardware) + { + hardware.Update(); + + foreach (var sensor in hardware.Sensors) + { + if (sensor.Value.HasValue) + { + string sensorId = GetSensorVariableName(hardware.Name, sensor.Name); + sensorValues[sensorId] = sensor.Value.Value; + } + } + } + } + + /// + /// Gets a dictionary of all current sensor values + /// + public Dictionary GetAllSensorValues() + { + return new Dictionary(sensorValues); + } + + /// + /// Gets the value of a specific sensor + /// + public float? GetSensorValue(string sensorId) + { + if (sensorValues.TryGetValue(sensorId, out float value)) + { + return value; + } + return null; + } + + /// + /// Finds the first available sensor of a specific type + /// + public string FindFirstSensorOfType(HardwareType hardwareType, SensorType sensorType) + { + foreach (var hardware in computer.Hardware) + { + if (hardware.HardwareType == hardwareType) + { + foreach (var sensor in hardware.Sensors) + { + if (sensor.SensorType == sensorType && sensor.Value.HasValue) + { + return GetSensorVariableName(hardware.Name, sensor.Name); + } + } + } + } + return string.Empty; + } + + /// + /// Creates a variable name for a sensor that's safe to use in markup + /// + public static string GetSensorVariableName(string hardwareName, string sensorName) + { + string name = $"{hardwareName}_{sensorName}" + .Replace(" ", "_") + .Replace("%", "Percent") + .Replace("#", "Num") + .Replace("/", "_") + .Replace("\\", "_") + .Replace("(", "") + .Replace(")", "") + .Replace(",", ""); + + return name; + } + + /// + /// Gets the appropriate unit for a sensor type + /// + public static string GetSensorUnit(SensorType sensorType) + { + return sensorType switch + { + SensorType.Temperature => "°C", + SensorType.Load => "%", + SensorType.Clock => "MHz", + SensorType.Power => "W", + SensorType.Fan => "RPM", + SensorType.Flow => "L/h", + SensorType.Control => "%", + SensorType.Level => "%", + _ => "" + }; + } + + /// + /// Formats a sensor value according to its type + /// + public static string FormatSensorValue(float value, SensorType sensorType) + { + return sensorType switch + { + SensorType.Temperature => value.ToString("F1"), + SensorType.Clock => value.ToString("F0"), + SensorType.Load => value.ToString("F1"), + SensorType.Fan => value.ToString("F0"), + SensorType.Power => value.ToString("F1"), + SensorType.Data => (value > 1024) ? (value / 1024).ToString("F1") : value.ToString("F1"), + _ => value.ToString("F1") + }; + } + + /// + /// Gets all hardware sensors grouped by type + /// + public Dictionary> GetAllSensorsGroupedByType() + { + var result = new Dictionary>(); + + foreach (var hardware in computer.Hardware) + { + hardware.Update(); + foreach (var sensor in hardware.Sensors) + { + if (sensor.Value.HasValue) + { + var sensorType = sensor.SensorType; + if (!result.ContainsKey(sensorType)) + { + result[sensorType] = new List(); + } + + string sensorId = GetSensorVariableName(hardware.Name, sensor.Name); + result[sensorType].Add(new SensorInfo + { + Id = sensorId, + Name = $"{hardware.Name} {sensor.Name}", + Value = sensor.Value.Value, + SensorType = sensorType + }); + } + } + } + + return result; + } + + /// + /// Gets all hardware for populating dropdown lists + /// + public List GetSensorOptionsForDropdown() + { + var options = new List(); + + foreach (var hardware in computer.Hardware) + { + hardware.Update(); + foreach (var sensor in hardware.Sensors) + { + if (sensor.SensorType == SensorType.Load || + sensor.SensorType == SensorType.Temperature || + sensor.SensorType == SensorType.Data || + sensor.SensorType == SensorType.Fan) + { + string option = $"{hardware.HardwareType}: {sensor.Name} ({sensor.SensorType})"; + options.Add(option); + } + } + } + + options.Add("Custom Text"); + return options; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!isDisposed) + { + if (disposing) + { + computer.Close(); + } + + isDisposed = true; + } + } + } + + /// + /// Represents information about a sensor + /// + public class SensorInfo + { + public string Id { get; set; } + public string Name { get; set; } + public float Value { get; set; } + public SensorType SensorType { get; set; } + } +} \ No newline at end of file diff --git a/PCPalConfigurator/PCPalConfigurator.csproj b/PCPalConfigurator/PCPalConfigurator.csproj index acd2bae..c633554 100644 --- a/PCPalConfigurator/PCPalConfigurator.csproj +++ b/PCPalConfigurator/PCPalConfigurator.csproj @@ -28,10 +28,4 @@ - - - - - - \ No newline at end of file diff --git a/PCPalConfigurator/PCPalConfigurator.csproj.user b/PCPalConfigurator/PCPalConfigurator.csproj.user index 06b365e..e84a3a9 100644 --- a/PCPalConfigurator/PCPalConfigurator.csproj.user +++ b/PCPalConfigurator/PCPalConfigurator.csproj.user @@ -1,11 +1,14 @@  - + Form - + Form + + Component + \ No newline at end of file diff --git a/PCPalConfigurator/Program.cs b/PCPalConfigurator/Program.cs index 0406e33..4df1b74 100644 --- a/PCPalConfigurator/Program.cs +++ b/PCPalConfigurator/Program.cs @@ -1,14 +1,21 @@ +using System; +using System.Windows.Forms; +using PCPalConfigurator.UI; + namespace PCPalConfigurator { static class Program { + /// + /// The main entry point for the application. + /// [STAThread] static void Main() { + Application.SetHighDpiMode(HighDpiMode.SystemAware); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new ConfiguratorForm()); } } - } \ No newline at end of file diff --git a/PCPalConfigurator/Rendering/Elements/BarElement.cs b/PCPalConfigurator/Rendering/Elements/BarElement.cs new file mode 100644 index 0000000..f966e62 --- /dev/null +++ b/PCPalConfigurator/Rendering/Elements/BarElement.cs @@ -0,0 +1,30 @@ +using System.Drawing; + +namespace PCPalConfigurator.Rendering.Elements +{ + /// + /// Represents a bar graph element in the OLED preview + /// + public class BarElement : PreviewElement + { + public int X { get; set; } + public int Y { get; set; } + public int Width { get; set; } + public int Height { get; set; } + public int Value { get; set; } + + public override void Draw(Graphics g) + { + // Draw outline rectangle + g.DrawRectangle(Pens.White, X, Y, Width, Height); + + // Calculate fill width based on value (0-100) + int fillWidth = (int)(Width * (Value / 100.0)); + if (fillWidth > 0) + { + // Draw filled portion + g.FillRectangle(Brushes.White, X + 1, Y + 1, fillWidth - 1, Height - 2); + } + } + } +} \ No newline at end of file diff --git a/PCPalConfigurator/Rendering/Elements/IconElement.cs b/PCPalConfigurator/Rendering/Elements/IconElement.cs new file mode 100644 index 0000000..efde526 --- /dev/null +++ b/PCPalConfigurator/Rendering/Elements/IconElement.cs @@ -0,0 +1,24 @@ +using System.Drawing; + +namespace PCPalConfigurator.Rendering.Elements +{ + /// + /// Represents an icon element in the OLED preview + /// + public class IconElement : PreviewElement + { + public int X { get; set; } + public int Y { get; set; } + public string Name { get; set; } + + public override void Draw(Graphics g) + { + // For preview, just draw a placeholder rectangle with icon name + g.DrawRectangle(Pens.Gray, X, Y, 24, 24); + using (Font font = new Font("Arial", 6)) + { + g.DrawString(Name, font, Brushes.White, X + 2, Y + 8); + } + } + } +} \ No newline at end of file diff --git a/PCPalConfigurator/Rendering/Elements/LineElement.cs b/PCPalConfigurator/Rendering/Elements/LineElement.cs new file mode 100644 index 0000000..6c8412e --- /dev/null +++ b/PCPalConfigurator/Rendering/Elements/LineElement.cs @@ -0,0 +1,20 @@ +using System.Drawing; + +namespace PCPalConfigurator.Rendering.Elements +{ + /// + /// Represents a line element in the OLED preview + /// + public class LineElement : PreviewElement + { + public int X1 { get; set; } + public int Y1 { get; set; } + public int X2 { get; set; } + public int Y2 { get; set; } + + public override void Draw(Graphics g) + { + g.DrawLine(Pens.White, X1, Y1, X2, Y2); + } + } +} \ No newline at end of file diff --git a/PCPalConfigurator/Rendering/Elements/RectElement.cs b/PCPalConfigurator/Rendering/Elements/RectElement.cs new file mode 100644 index 0000000..2543359 --- /dev/null +++ b/PCPalConfigurator/Rendering/Elements/RectElement.cs @@ -0,0 +1,30 @@ +using System.Drawing; + +namespace PCPalConfigurator.Rendering.Elements +{ + /// + /// Represents a rectangle or box element in the OLED preview + /// + public class RectElement : PreviewElement + { + public int X { get; set; } + public int Y { get; set; } + public int Width { get; set; } + public int Height { get; set; } + public bool Filled { get; set; } + + public override void Draw(Graphics g) + { + if (Filled) + { + // Draw filled box + g.FillRectangle(Brushes.White, X, Y, Width, Height); + } + else + { + // Draw outline rectangle + g.DrawRectangle(Pens.White, X, Y, Width, Height); + } + } + } +} \ No newline at end of file diff --git a/PCPalConfigurator/Rendering/Elements/TextElement.cs b/PCPalConfigurator/Rendering/Elements/TextElement.cs new file mode 100644 index 0000000..ac36583 --- /dev/null +++ b/PCPalConfigurator/Rendering/Elements/TextElement.cs @@ -0,0 +1,31 @@ +using System.Drawing; + +namespace PCPalConfigurator.Rendering.Elements +{ + /// + /// Represents a text element in the OLED preview + /// + public class TextElement : PreviewElement + { + public int X { get; set; } + public int Y { get; set; } + public int Size { get; set; } + public string Text { get; set; } + + public override void Draw(Graphics g) + { + // Choose font size based on the size parameter + Font font; + switch (Size) + { + case 1: font = new Font("Consolas", 8); break; + case 2: font = new Font("Consolas", 10); break; + case 3: font = new Font("Consolas", 12); break; + default: font = new Font("Consolas", 8); break; + } + + // Draw text with white color + g.DrawString(Text, font, Brushes.White, X, Y - font.Height); + } + } +} \ No newline at end of file diff --git a/PCPalConfigurator/Rendering/PreviewElement.cs b/PCPalConfigurator/Rendering/PreviewElement.cs new file mode 100644 index 0000000..abb9a04 --- /dev/null +++ b/PCPalConfigurator/Rendering/PreviewElement.cs @@ -0,0 +1,15 @@ +using System.Drawing; + +namespace PCPalConfigurator.Rendering +{ + /// + /// Base class for all OLED preview elements + /// + public abstract class PreviewElement + { + /// + /// Draws the element on the provided graphics context + /// + public abstract void Draw(Graphics g); + } +} \ No newline at end of file diff --git a/PCPalConfigurator/Rendering/RenderPreview.cs b/PCPalConfigurator/Rendering/RenderPreview.cs new file mode 100644 index 0000000..0db987a --- /dev/null +++ b/PCPalConfigurator/Rendering/RenderPreview.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Drawing2D; + +namespace PCPalConfigurator.Rendering +{ + /// + /// Renders OLED preview elements to a graphics context + /// + public class OledRenderer + { + private const int OledWidth = 256; + private const int OledHeight = 64; + + /// + /// Renders a list of preview elements to a graphics context + /// + public void RenderPreview(Graphics g, List elements, int panelWidth, int panelHeight) + { + // Create graphics object with smooth rendering + g.SmoothingMode = SmoothingMode.AntiAlias; + + // Calculate scale to fit preview in panel while maintaining aspect ratio + float scaleX = (float)panelWidth / OledWidth; + float scaleY = (float)panelHeight / OledHeight; + float scale = Math.Min(scaleX, scaleY); + + // Calculate centered position + int displayWidth = (int)(OledWidth * scale); + int displayHeight = (int)(OledHeight * scale); + int offsetX = (panelWidth - displayWidth) / 2; + int offsetY = (panelHeight - displayHeight) / 2; + + // Draw display outline + Rectangle displayRect = new Rectangle(offsetX, offsetY, displayWidth, displayHeight); + g.DrawRectangle(Pens.DarkGray, displayRect); + + // Set up transformation to scale the preview elements + g.TranslateTransform(offsetX, offsetY); + g.ScaleTransform(scale, scale); + + // Draw all elements + foreach (var element in elements) + { + element.Draw(g); + } + + // Reset transformation + g.ResetTransform(); + + // Draw labels and guidelines + g.DrawString($"OLED: {OledWidth}x{OledHeight}", new Font("Arial", 8), Brushes.Gray, 5, 5); + } + + /// + /// Gets the OLED display dimensions + /// + public static (int Width, int Height) GetDisplayDimensions() + { + return (OledWidth, OledHeight); + } + } +} \ No newline at end of file diff --git a/PCPalConfigurator/UI/ConfiguratorForm.Designer.cs b/PCPalConfigurator/UI/ConfiguratorForm.Designer.cs new file mode 100644 index 0000000..10535c3 --- /dev/null +++ b/PCPalConfigurator/UI/ConfiguratorForm.Designer.cs @@ -0,0 +1,256 @@ +using PCPalConfigurator.Rendering; +using PCPalConfigurator.UI; + +namespace PCPalConfigurator.UI +{ + partial class ConfiguratorForm + { + private System.ComponentModel.IContainer components = null; + + private System.Windows.Forms.TabControl tabControl; + private System.Windows.Forms.TabPage tab1602; + private System.Windows.Forms.TabPage tabTFT; + private System.Windows.Forms.TabPage tabOLED; + private System.Windows.Forms.TabPage tabHelp; + private System.Windows.Forms.TabPage tabAbout; + + private System.Windows.Forms.ComboBox cmbLine1; + private System.Windows.Forms.TextBox txtLine1; + private System.Windows.Forms.TextBox txtLine1Post; + private System.Windows.Forms.ComboBox cmbLine2; + private System.Windows.Forms.TextBox txtLine2; + private System.Windows.Forms.TextBox txtLine2Post; + private System.Windows.Forms.Button btnSave; + + private System.Windows.Forms.Label lblLine1; + private System.Windows.Forms.Label lblLine1Prefix; + private System.Windows.Forms.Label lblLine1Suffix; + private System.Windows.Forms.Label lblLine2; + private System.Windows.Forms.Label lblLine2Prefix; + private System.Windows.Forms.Label lblLine2Suffix; + + // OLED tab controls + private System.Windows.Forms.TextBox txtOledMarkup; + private System.Windows.Forms.Panel panelOledButtons; + private System.Windows.Forms.Button btnInsertIcon; + private System.Windows.Forms.Button btnLoadOledExample; + private System.Windows.Forms.Button btnSaveOled; + private System.Windows.Forms.Button btnPreview; + private System.Windows.Forms.Label lblPreviewHeader; + private OledPreviewPanel oledPreviewPanel; + + // Help tab controls + private System.Windows.Forms.TextBox txtHelpContent; + + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + components.Dispose(); + + base.Dispose(disposing); + } + + private void InitializeComponent() + { + this.tabControl = new System.Windows.Forms.TabControl(); + this.tab1602 = new System.Windows.Forms.TabPage("1602 LCD"); + this.tabTFT = new System.Windows.Forms.TabPage("4.6\" TFT LCD"); + this.tabOLED = new System.Windows.Forms.TabPage("OLED Display"); + this.tabHelp = new System.Windows.Forms.TabPage("Help"); + this.tabAbout = new System.Windows.Forms.TabPage("About"); + + this.cmbLine1 = new System.Windows.Forms.ComboBox(); + this.txtLine1 = new System.Windows.Forms.TextBox(); + this.txtLine1Post = new System.Windows.Forms.TextBox(); + this.cmbLine2 = new System.Windows.Forms.ComboBox(); + this.txtLine2 = new System.Windows.Forms.TextBox(); + this.txtLine2Post = new System.Windows.Forms.TextBox(); + this.btnSave = new System.Windows.Forms.Button(); + + this.lblLine1 = new System.Windows.Forms.Label(); + this.lblLine1Prefix = new System.Windows.Forms.Label(); + this.lblLine1Suffix = new System.Windows.Forms.Label(); + this.lblLine2 = new System.Windows.Forms.Label(); + this.lblLine2Prefix = new System.Windows.Forms.Label(); + this.lblLine2Suffix = new System.Windows.Forms.Label(); + + // OLED tab controls + this.txtOledMarkup = new System.Windows.Forms.TextBox(); + this.panelOledButtons = new System.Windows.Forms.Panel(); + this.btnInsertIcon = new System.Windows.Forms.Button(); + this.btnLoadOledExample = new System.Windows.Forms.Button(); + this.btnSaveOled = new System.Windows.Forms.Button(); + this.btnPreview = new System.Windows.Forms.Button(); + this.lblPreviewHeader = new System.Windows.Forms.Label(); + this.oledPreviewPanel = new OledPreviewPanel(); + + // Help tab controls + this.txtHelpContent = new System.Windows.Forms.TextBox(); + + // === TabControl === + this.tabControl.Dock = System.Windows.Forms.DockStyle.Fill; + this.tabControl.TabPages.Add(this.tab1602); + this.tabControl.TabPages.Add(this.tabTFT); + this.tabControl.TabPages.Add(this.tabOLED); + this.tabControl.TabPages.Add(this.tabHelp); + this.tabControl.TabPages.Add(this.tabAbout); + this.Controls.Add(this.tabControl); + + // === Line 1 UI === + this.lblLine1.Text = "Line 1:"; + this.lblLine1.Location = new System.Drawing.Point(20, 20); + this.lblLine1.AutoSize = true; + + this.cmbLine1.Location = new System.Drawing.Point(100, 18); + this.cmbLine1.Size = new System.Drawing.Size(200, 21); + + this.lblLine1Prefix.Text = "Prefix:"; + this.lblLine1Prefix.Location = new System.Drawing.Point(20, 50); + this.lblLine1Prefix.AutoSize = true; + + this.txtLine1.Location = new System.Drawing.Point(100, 48); + this.txtLine1.Size = new System.Drawing.Size(200, 21); + + this.lblLine1Suffix.Text = "Suffix / Units:"; + this.lblLine1Suffix.Location = new System.Drawing.Point(320, 50); + this.lblLine1Suffix.AutoSize = true; + + this.txtLine1Post.Location = new System.Drawing.Point(420, 48); + this.txtLine1Post.Size = new System.Drawing.Size(120, 21); + + // === Line 2 UI === + this.lblLine2.Text = "Line 2:"; + this.lblLine2.Location = new System.Drawing.Point(20, 90); + this.lblLine2.AutoSize = true; + + this.cmbLine2.Location = new System.Drawing.Point(100, 88); + this.cmbLine2.Size = new System.Drawing.Size(200, 21); + + this.lblLine2Prefix.Text = "Prefix:"; + this.lblLine2Prefix.Location = new System.Drawing.Point(20, 120); + this.lblLine2Prefix.AutoSize = true; + + this.txtLine2.Location = new System.Drawing.Point(100, 118); + this.txtLine2.Size = new System.Drawing.Size(200, 21); + + this.lblLine2Suffix.Text = "Suffix / Units:"; + this.lblLine2Suffix.Location = new System.Drawing.Point(320, 120); + this.lblLine2Suffix.AutoSize = true; + + this.txtLine2Post.Location = new System.Drawing.Point(420, 118); + this.txtLine2Post.Size = new System.Drawing.Size(120, 21); + + // === Save Button === + this.btnSave.Text = "Save"; + this.btnSave.Location = new System.Drawing.Point(20, 170); + this.btnSave.Size = new System.Drawing.Size(100, 30); + this.btnSave.Click += new System.EventHandler(this.btnSave_Click); + + // === Add to 1602 Tab === + this.tab1602.Controls.AddRange(new System.Windows.Forms.Control[] + { + lblLine1, cmbLine1, lblLine1Prefix, txtLine1, lblLine1Suffix, txtLine1Post, + lblLine2, cmbLine2, lblLine2Prefix, txtLine2, lblLine2Suffix, txtLine2Post, + btnSave + }); + + // === OLED Tab Setup === + // Main panel for layout + System.Windows.Forms.Panel oledMainPanel = new System.Windows.Forms.Panel(); + oledMainPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tabOLED.Controls.Add(oledMainPanel); + + // Markup editor + this.txtOledMarkup = new System.Windows.Forms.TextBox(); + this.txtOledMarkup.Multiline = true; + this.txtOledMarkup.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.txtOledMarkup.Font = new System.Drawing.Font("Consolas", 9.75F); + this.txtOledMarkup.TextChanged += new System.EventHandler(this.txtOledMarkup_TextChanged); + this.txtOledMarkup.Size = new System.Drawing.Size(580, 130); + this.txtOledMarkup.Location = new System.Drawing.Point(10, 10); + oledMainPanel.Controls.Add(this.txtOledMarkup); + + // Button panel + this.panelOledButtons = new System.Windows.Forms.Panel(); + this.panelOledButtons.Size = new System.Drawing.Size(580, 40); + this.panelOledButtons.Location = new System.Drawing.Point(10, 150); + oledMainPanel.Controls.Add(this.panelOledButtons); + + this.btnInsertIcon = new System.Windows.Forms.Button(); + this.btnInsertIcon.Text = "Insert Icon"; + this.btnInsertIcon.Location = new System.Drawing.Point(0, 7); + this.btnInsertIcon.Size = new System.Drawing.Size(120, 26); + this.btnInsertIcon.Click += new System.EventHandler(this.btnInsertIcon_Click); + this.panelOledButtons.Controls.Add(this.btnInsertIcon); + + this.btnLoadOledExample = new System.Windows.Forms.Button(); + this.btnLoadOledExample.Text = "Load Example"; + this.btnLoadOledExample.Location = new System.Drawing.Point(130, 7); + this.btnLoadOledExample.Size = new System.Drawing.Size(120, 26); + this.btnLoadOledExample.Click += new System.EventHandler(this.btnLoadOledExample_Click); + this.panelOledButtons.Controls.Add(this.btnLoadOledExample); + + this.btnPreview = new System.Windows.Forms.Button(); + this.btnPreview.Text = "Update Preview"; + this.btnPreview.Location = new System.Drawing.Point(260, 7); + this.btnPreview.Size = new System.Drawing.Size(120, 26); + this.btnPreview.Click += new System.EventHandler(this.btnPreview_Click); + this.panelOledButtons.Controls.Add(this.btnPreview); + + this.btnSaveOled = new System.Windows.Forms.Button(); + this.btnSaveOled.Text = "Save"; + this.btnSaveOled.Location = new System.Drawing.Point(480, 7); + this.btnSaveOled.Size = new System.Drawing.Size(100, 26); + this.btnSaveOled.Click += new System.EventHandler(this.btnSave_Click); // Uses same event handler + this.panelOledButtons.Controls.Add(this.btnSaveOled); + + // Preview header + this.lblPreviewHeader = new System.Windows.Forms.Label(); + this.lblPreviewHeader.Text = "OLED Preview (256x64)"; + this.lblPreviewHeader.Location = new System.Drawing.Point(10, 195); + this.lblPreviewHeader.Size = new System.Drawing.Size(580, 20); + this.lblPreviewHeader.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.lblPreviewHeader.BackColor = System.Drawing.SystemColors.ControlLight; + this.lblPreviewHeader.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + oledMainPanel.Controls.Add(this.lblPreviewHeader); + + // Preview panel + this.oledPreviewPanel.Location = new System.Drawing.Point(10, 215); + this.oledPreviewPanel.Size = new System.Drawing.Size(580, 110); + oledMainPanel.Controls.Add(this.oledPreviewPanel); + + // === Help Tab Setup === + this.txtHelpContent = new System.Windows.Forms.TextBox(); + this.txtHelpContent.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtHelpContent.Multiline = true; + this.txtHelpContent.ReadOnly = true; + this.txtHelpContent.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.txtHelpContent.Font = new System.Drawing.Font("Segoe UI", 9F); + this.tabHelp.Controls.Add(this.txtHelpContent); + + // === TFT Tab Placeholder === + System.Windows.Forms.Label lblTFT = new System.Windows.Forms.Label() + { + Text = "TFT configuration coming soon...", + Location = new System.Drawing.Point(20, 20), + AutoSize = true + }; + this.tabTFT.Controls.Add(lblTFT); + + // === About Tab === + System.Windows.Forms.Label lblAbout = new System.Windows.Forms.Label() + { + Text = "PCPal Display Configurator\nFor ThermalTake Tower XXX\nVersion 1.0.0\n© 2025 Christopher Koch aka NinjaPug", + Location = new System.Drawing.Point(20, 20), + AutoSize = true + }; + this.tabAbout.Controls.Add(lblAbout); + + // === Form === + this.Text = "Display Configurator"; + this.ClientSize = new System.Drawing.Size(600, 380); + this.ResumeLayout(false); + this.PerformLayout(); + } + } +} \ No newline at end of file diff --git a/PCPalConfigurator/UI/ConfiguratorForm.cs b/PCPalConfigurator/UI/ConfiguratorForm.cs new file mode 100644 index 0000000..b9232da --- /dev/null +++ b/PCPalConfigurator/UI/ConfiguratorForm.cs @@ -0,0 +1,292 @@ +using System; +using System.IO; +using System.Text; +using System.Windows.Forms; +using System.Collections.Generic; +using Newtonsoft.Json; + +using PCPalConfigurator.Core; +using PCPalConfigurator.Rendering; + +namespace PCPalConfigurator.UI +{ + public partial class ConfiguratorForm : Form + { + private ConfigData config; + private readonly string configFile; + private SensorManager sensorManager; + private System.Windows.Forms.Timer sensorUpdateTimer; + private MarkupParser markupParser; + private List previewElements = new List(); + + public ConfiguratorForm() + { + InitializeComponent(); + + // Initialize the configuration path + configFile = GetConfigPath(); + + // Initialize hardware monitoring + sensorManager = new SensorManager(); + sensorManager.UpdateSensorValues(); + + // Initialize markup parser + markupParser = new MarkupParser(sensorManager.GetAllSensorValues()); + + // Setup timer for sensor updates + InitSensorTimer(); + + // Load configuration and populate UI + LoadConfig(); + PopulateSensorOptions(); + PopulateHelpContent(); + + // Initial preview update + UpdatePreview(); + } + + private void InitSensorTimer() + { + // Create a timer to regularly update sensor values for the preview + sensorUpdateTimer = new System.Windows.Forms.Timer(); + sensorUpdateTimer.Interval = 1000; // Update every second + sensorUpdateTimer.Tick += SensorUpdateTimer_Tick; + sensorUpdateTimer.Start(); + } + + private void SensorUpdateTimer_Tick(object sender, EventArgs e) + { + // Only update when the OLED tab is selected to save resources + if (tabControl.SelectedTab == tabOLED) + { + sensorManager.UpdateSensorValues(); + markupParser = new MarkupParser(sensorManager.GetAllSensorValues()); + UpdatePreview(); + } + } + + private static string GetConfigPath() + { + string folder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "PCPal"); + Directory.CreateDirectory(folder); + return Path.Combine(folder, "config.json"); + } + + private void LoadConfig() + { + if (File.Exists(configFile)) + { + string json = File.ReadAllText(configFile); + config = JsonConvert.DeserializeObject(json) ?? new ConfigData(); + ApplyConfig(); + } + else + { + config = new ConfigData(); + } + } + + private void ApplyConfig() + { + // LCD settings + cmbLine1.SelectedItem = config.Line1Selection; + txtLine1.Text = config.Line1CustomText; + txtLine1Post.Text = config.Line1PostText; + cmbLine2.SelectedItem = config.Line2Selection; + txtLine2.Text = config.Line2CustomText; + txtLine2Post.Text = config.Line2PostText; + + // OLED settings + txtOledMarkup.Text = config.OledMarkup; + + // Select the appropriate tab based on screen type + if (config.ScreenType == "1602") + tabControl.SelectedTab = tab1602; + else if (config.ScreenType == "TFT4_6") + tabControl.SelectedTab = tabTFT; + else if (config.ScreenType == "OLED") + tabControl.SelectedTab = tabOLED; + } + + private void SaveConfig() + { + // Determine screen type based on selected tab + if (tabControl.SelectedTab == tab1602) + config.ScreenType = "1602"; + else if (tabControl.SelectedTab == tabTFT) + config.ScreenType = "TFT4_6"; + else if (tabControl.SelectedTab == tabOLED) + config.ScreenType = "OLED"; + + // Save LCD settings + config.Line1Selection = cmbLine1.SelectedItem?.ToString(); + config.Line1CustomText = txtLine1.Text; + config.Line1PostText = txtLine1Post.Text; + config.Line2Selection = cmbLine2.SelectedItem?.ToString(); + config.Line2CustomText = txtLine2.Text; + config.Line2PostText = txtLine2Post.Text; + + // Save OLED settings + config.OledMarkup = txtOledMarkup.Text; + + string json = JsonConvert.SerializeObject(config, Formatting.Indented); + File.WriteAllText(configFile, json); + MessageBox.Show("Settings saved!"); + } + + private void btnSave_Click(object sender, EventArgs e) + { + SaveConfig(); + } + + private void PopulateSensorOptions() + { + var options = sensorManager.GetSensorOptionsForDropdown(); + + cmbLine1.Items.Clear(); + cmbLine2.Items.Clear(); + + foreach (var option in options) + { + cmbLine1.Items.Add(option); + cmbLine2.Items.Add(option); + } + } + + private void PopulateHelpContent() + { + // Create help content for both LCD and OLED displays + StringBuilder sb = new StringBuilder(); + + // General Information + sb.AppendLine("PCPal Display Configurator Help"); + sb.AppendLine("=============================="); + sb.AppendLine(); + + // LCD Display Help + sb.AppendLine("LCD DISPLAY CONFIGURATION"); + sb.AppendLine("------------------------"); + sb.AppendLine("1. Select a sensor for each line or choose 'Custom Text'"); + sb.AppendLine("2. Set prefix text to appear before the sensor value"); + sb.AppendLine("3. Set suffix/units to appear after the sensor value"); + sb.AppendLine("4. Click 'Save' to apply your settings"); + sb.AppendLine(); + + // OLED Display Help + sb.AppendLine("OLED MARKUP REFERENCE"); + sb.AppendLine("---------------------"); + sb.AppendLine("The OLED display accepts markup tags to create your layout."); + sb.AppendLine(); + sb.AppendLine("Text: Hello World"); + sb.AppendLine(" - x, y: position coordinates (0,0 is top-left)"); + sb.AppendLine(" - size: 1-3 (small to large)"); + sb.AppendLine(); + sb.AppendLine("Progress Bar: "); + sb.AppendLine(" - x, y: position"); + sb.AppendLine(" - w, h: width and height"); + sb.AppendLine(" - val: value 0-100"); + sb.AppendLine(); + sb.AppendLine("Icon: "); + sb.AppendLine(" - Inserts a bitmap icon from the SD card"); + sb.AppendLine(" - Use the 'Insert Icon' button to browse available icons"); + sb.AppendLine(); + sb.AppendLine("Rectangle (outline): "); + sb.AppendLine(); + sb.AppendLine("Filled Box: "); + sb.AppendLine(); + sb.AppendLine("Line: "); + sb.AppendLine(); + + // Sensor variables + sb.AppendLine("SENSOR VARIABLES"); + sb.AppendLine("----------------"); + sb.AppendLine("Use {SensorName} syntax to include sensor values."); + sb.AppendLine("Example: CPU: {CPU_Core_i7_Total_Load}%"); + + // Add available sensor variables with their current values + sb.AppendLine(); + sb.AppendLine("Available sensor variables:"); + + var sensorGroups = sensorManager.GetAllSensorsGroupedByType(); + foreach (var group in sensorGroups) + { + sb.AppendLine(); + sb.AppendLine($"-- {group.Key} Sensors --"); + + foreach (var sensor in group.Value) // Change here - iterate over group.Value + { + string unit = SensorManager.GetSensorUnit(group.Key); + string value = SensorManager.FormatSensorValue(sensor.Value, group.Key); + sb.AppendLine($"{{{sensor.Id}}} = {value}{unit} ({sensor.Name})"); + } + } + + txtHelpContent.Text = sb.ToString(); + } + + private void btnInsertIcon_Click(object sender, EventArgs e) + { + using (var browser = new IconBrowser()) + { + if (browser.ShowDialog() == DialogResult.OK) + { + // Get the icon markup and insert it at the cursor position + string iconMarkup = browser.GetIconMarkup(); + if (!string.IsNullOrEmpty(iconMarkup)) + { + int selectionStart = txtOledMarkup.SelectionStart; + txtOledMarkup.Text = txtOledMarkup.Text.Insert(selectionStart, iconMarkup); + txtOledMarkup.SelectionStart = selectionStart + iconMarkup.Length; + txtOledMarkup.Focus(); + } + } + } + } + + private void btnLoadOledExample_Click(object sender, EventArgs e) + { + // Create an example with sensors from the current system + string exampleMarkup = MarkupParser.CreateExampleMarkup(sensorManager); + txtOledMarkup.Text = exampleMarkup; + } + + private void btnPreview_Click(object sender, EventArgs e) + { + sensorManager.UpdateSensorValues(); + markupParser = new MarkupParser(sensorManager.GetAllSensorValues()); + UpdatePreview(); + } + + private void txtOledMarkup_TextChanged(object sender, EventArgs e) + { + UpdatePreview(); + } + + private void UpdatePreview() + { + try + { + // Parse the markup into preview elements + previewElements = markupParser.ParseMarkup(txtOledMarkup.Text); + + // Update the preview panel + oledPreviewPanel.SetPreviewElements(previewElements); + } + catch (Exception ex) + { + // Don't show errors during preview - just log them + Console.WriteLine($"Preview error: {ex.Message}"); + } + } + + protected override void OnFormClosing(FormClosingEventArgs e) + { + base.OnFormClosing(e); + + // Clean up resources + sensorUpdateTimer?.Stop(); + sensorUpdateTimer?.Dispose(); + sensorManager?.Dispose(); + } + } +} \ No newline at end of file diff --git a/PCPalConfigurator/ConfiguratorForm.resx b/PCPalConfigurator/UI/ConfiguratorForm.resx similarity index 100% rename from PCPalConfigurator/ConfiguratorForm.resx rename to PCPalConfigurator/UI/ConfiguratorForm.resx diff --git a/PCPalConfigurator/IconBrowser/IconBrowser.Designer.cs b/PCPalConfigurator/UI/IconBrowser.Designer.cs similarity index 99% rename from PCPalConfigurator/IconBrowser/IconBrowser.Designer.cs rename to PCPalConfigurator/UI/IconBrowser.Designer.cs index 0018372..1ae0990 100644 --- a/PCPalConfigurator/IconBrowser/IconBrowser.Designer.cs +++ b/PCPalConfigurator/UI/IconBrowser.Designer.cs @@ -1,4 +1,7 @@ -namespace PCPalConfigurator +using System.Windows.Forms; +using System.Drawing; + +namespace PCPalConfigurator.UI { partial class IconBrowser { diff --git a/PCPalConfigurator/IconBrowser/IconBrowser.cs b/PCPalConfigurator/UI/IconBrowser.cs similarity index 98% rename from PCPalConfigurator/IconBrowser/IconBrowser.cs rename to PCPalConfigurator/UI/IconBrowser.cs index d2941b6..6173e2d 100644 --- a/PCPalConfigurator/IconBrowser/IconBrowser.cs +++ b/PCPalConfigurator/UI/IconBrowser.cs @@ -4,8 +4,11 @@ using System.Drawing; using System.IO; using System.Windows.Forms; -namespace PCPalConfigurator +namespace PCPalConfigurator.UI { + /// + /// Dialog for browsing and selecting icons + /// public partial class IconBrowser : Form { private string _selectedIconPath = ""; diff --git a/PCPalConfigurator/IconBrowser/IconBrowser.resx b/PCPalConfigurator/UI/IconBrowser.resx similarity index 100% rename from PCPalConfigurator/IconBrowser/IconBrowser.resx rename to PCPalConfigurator/UI/IconBrowser.resx diff --git a/PCPalConfigurator/UI/OledPreviewPanel.cs b/PCPalConfigurator/UI/OledPreviewPanel.cs new file mode 100644 index 0000000..ac010a5 --- /dev/null +++ b/PCPalConfigurator/UI/OledPreviewPanel.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Windows.Forms; +using PCPalConfigurator.Rendering; + +namespace PCPalConfigurator.UI +{ + /// + /// Custom panel for displaying OLED preview + /// + public class OledPreviewPanel : Panel + { + private List previewElements = new List(); + private readonly OledRenderer renderer = new OledRenderer(); + + public OledPreviewPanel() + { + this.BackColor = Color.Black; + this.BorderStyle = BorderStyle.FixedSingle; + this.DoubleBuffered = true; // Reduces flicker during repaints + } + + /// + /// Updates the preview elements to be rendered + /// + public void SetPreviewElements(List elements) + { + previewElements = elements ?? new List(); + this.Invalidate(); // Trigger a repaint + } + + /// + /// Handles the paint event to render the OLED preview + /// + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + + // Render the preview elements + renderer.RenderPreview(e.Graphics, previewElements, this.Width, this.Height); + } + } +} \ No newline at end of file