Files
HawkeyeVision/VisionBuilder.UI.IOCommander.Windows/WindowsIOCommanderDebugViewService.cs
2025-07-19 15:57:59 +02:00

219 lines
8.0 KiB
C#

using System.Drawing;
using System.Windows.Forms;
using VisionBuilder.UI.IOCommander.Interfaces;
namespace VisionBuilder.UI.IOCommander.Windows
{
public partial class WindowsIOCommanderDebugViewService : Form, IIOCommanderDebugViewService
{
private readonly WindowsIOCommanderDebugViewSettings _settings;
private readonly Dictionary<int, PinIndicator> _inputPins = new();
private readonly Dictionary<int, PinIndicator> _outputPins = new();
private readonly object _lockObject = new object();
private bool _isVisible = false;
public WindowsIOCommanderDebugViewService(WindowsIOCommanderDebugViewSettings settings)
{
_settings = settings;
InitializeComponent();
InitializePinDisplay();
}
protected override void OnShown(EventArgs e)
{
this.TopMost = true;
this.Focus();
this.TopMost = true;
}
private void InitializePinDisplay()
{
// Configure form properties
this.Text = "IOCommander Debug View";
this.FormBorderStyle = FormBorderStyle.FixedToolWindow;
this.TopMost = true;
this.TopLevel = true;
this.ShowInTaskbar = false;
this.StartPosition = FormStartPosition.Manual;
this.Location = new Point(50, 50);
this.Size = new Size(280, 450); // Made wider to accommodate labels
this.BackColor = Color.FromArgb(64, 64, 64);
this.MinimizeBox = false;
this.MaximizeBox = false;
// Create pin indicators for input pins 1-20 and output pins 1-20 (20 rows, 2 columns)
int pinSize = 18;
int spacing = 2;
int centerX = 140; // Center the graphics in the wider form
int startY = 10;
// Get label dictionaries for quick lookup
var inputLabelDict = _settings.InputPinLabels?.ToDictionary(pl => pl.Pin, pl => pl.Label) ?? new Dictionary<int, string>();
var outputLabelDict = _settings.OutputPinLabels?.ToDictionary(pl => pl.Pin, pl => pl.Label) ?? new Dictionary<int, string>();
for (int row = 0; row < 20; row++)
{
int inputPin = row + 1; // Input pins numbered 1-20
int outputPin = row + 1; // Output pins numbered 1-20
// Left column (input pins)
var leftIndicator = new PinIndicator(inputPin, true)
{
Location = new Point(centerX - pinSize - spacing * 2, startY + (row * (pinSize + spacing))),
Size = new Size(pinSize, pinSize)
};
_inputPins[inputPin] = leftIndicator;
this.Controls.Add(leftIndicator);
// Right column (output pins)
var rightIndicator = new PinIndicator(outputPin, false)
{
Location = new Point(centerX + spacing * 2, startY + (row * (pinSize + spacing))),
Size = new Size(pinSize, pinSize)
};
_outputPins[outputPin] = rightIndicator;
this.Controls.Add(rightIndicator);
// Input pin label (left side - label before pin number)
string inputLabelText = inputLabelDict.ContainsKey(inputPin) ? $"{inputLabelDict[inputPin]} {inputPin}" : inputPin.ToString();
var leftLabel = new Label
{
Text = inputLabelText,
Location = new Point(5, startY + (row * (pinSize + spacing)) + 2),
Size = new Size(centerX - pinSize - spacing * 3 - 5, 14),
Font = new Font("Arial", 6, FontStyle.Bold),
ForeColor = Color.White,
BackColor = Color.Transparent,
TextAlign = ContentAlignment.MiddleRight
};
this.Controls.Add(leftLabel);
// Output pin label (right side - pin number followed by label)
string outputLabelText = outputLabelDict.ContainsKey(outputPin) ? $"{outputPin} {outputLabelDict[outputPin]}" : outputPin.ToString();
var rightLabel = new Label
{
Text = outputLabelText,
Location = new Point(centerX + pinSize + spacing * 3, startY + (row * (pinSize + spacing)) + 2),
Size = new Size(this.Width - (centerX + pinSize + spacing * 3) - 10, 14),
Font = new Font("Arial", 6, FontStyle.Bold),
ForeColor = Color.White,
BackColor = Color.Transparent,
TextAlign = ContentAlignment.MiddleLeft
};
this.Controls.Add(rightLabel);
}
}
public void SetInputPinStatus(int pin, bool state)
{
if (this.InvokeRequired)
{
this.Invoke(new Action(() => SetInputPinStatus(pin, state)));
return;
}
lock (_lockObject)
{
if (_inputPins.ContainsKey(pin))
{
_inputPins[pin].SetState(state);
}
}
}
public void SetOutputPinStatus(int pin, bool state)
{
if (this.InvokeRequired)
{
this.Invoke(new Action(() => SetOutputPinStatus(pin, state)));
return;
}
lock (_lockObject)
{
if (_outputPins.ContainsKey(pin))
{
_outputPins[pin].SetState(state);
}
}
}
public void ShowDebugView()
{
if (this.InvokeRequired)
{
this.Invoke(new Action(ShowDebugView));
return;
}
lock (_lockObject)
{
if (!_isVisible)
{
this.Show();
_isVisible = true;
}
}
}
private class PinIndicator : Control
{
private readonly int _pinNumber;
private readonly bool _isInput;
private bool _state = false;
private readonly SolidBrush _activeBrush;
private readonly SolidBrush _inactiveBrush;
public PinIndicator(int pinNumber, bool isInput)
{
_pinNumber = pinNumber;
_isInput = isInput;
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true);
// Input pins: Green when active, dark gray when inactive
// Output pins: Red when active, dark gray when inactive
if (_isInput)
{
_activeBrush = new SolidBrush(Color.Lime);
_inactiveBrush = new SolidBrush(Color.DarkGray);
}
else
{
_activeBrush = new SolidBrush(Color.Red);
_inactiveBrush = new SolidBrush(Color.DarkGray);
}
}
public void SetState(bool state)
{
if (_state != state)
{
_state = state;
this.Invalidate();
}
}
protected override void OnPaint(PaintEventArgs e)
{
var brush = _state ? _activeBrush : _inactiveBrush;
e.Graphics.FillEllipse(brush, 0, 0, Width - 1, Height - 1);
e.Graphics.DrawEllipse(Pens.Black, 0, 0, Width - 1, Height - 1);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_activeBrush?.Dispose();
_inactiveBrush?.Dispose();
}
base.Dispose(disposing);
}
}
}
}