using System; using System.Drawing; using System.IO; using System.Windows.Forms; using OpenCvSharp; using OpenCvSharp.Extensions; namespace Hawkeye.VisionBuilder.Features.ImagesStrip.Components { /// /// Represents a single image thumbnail item with an image and filename label. /// public class ImageThumbnailControl : Panel { private const int ThumbnailSize = 108; private const int BorderWidth = 3; private readonly PictureBox _pictureBox; private readonly Label _label; private bool _isSelected; private string _imagePath; public string ImagePath { get => _imagePath; set { _imagePath = value; LoadImage(value); _label.Text = Path.GetFileNameWithoutExtension(value); } } public bool IsSelected { get => _isSelected; set { if (_isSelected != value) { _isSelected = value; Invalidate(); // Trigger repaint to show/hide border } } } public event EventHandler ThumbnailClicked; public ImageThumbnailControl() { // Set up the container panel Width = ThumbnailSize + (BorderWidth * 2); Height = ThumbnailSize + 25 + (BorderWidth * 2); // Extra space for label Margin = new Padding(5); Cursor = Cursors.Hand; // Create PictureBox for the image _pictureBox = new PictureBox { Width = ThumbnailSize, Height = ThumbnailSize, SizeMode = PictureBoxSizeMode.StretchImage, Location = new System.Drawing.Point(BorderWidth, BorderWidth), BackColor = Color.Black }; _pictureBox.Click += OnThumbnailClick; // Create Label for the filename _label = new Label { Width = ThumbnailSize, Height = 20, Location = new System.Drawing.Point(BorderWidth, ThumbnailSize + BorderWidth + 2), TextAlign = ContentAlignment.MiddleCenter, AutoEllipsis = true, Font = new Font("Segoe UI", 8f) }; _label.Click += OnThumbnailClick; Controls.Add(_pictureBox); Controls.Add(_label); // Enable double buffering to reduce flicker DoubleBuffered = true; } private void LoadImage(string imagePath) { try { if (File.Exists(imagePath)) { using (var mat = new Mat(imagePath)) { var resized = mat.Resize(new OpenCvSharp.Size(ThumbnailSize, ThumbnailSize)); var bitmap = resized.ToBitmap(); // Dispose old image if exists var oldImage = _pictureBox.Image; _pictureBox.Image = bitmap; oldImage?.Dispose(); } } } catch (Exception ex) { // If image loading fails, show error in label _label.Text = "Error loading image"; _label.ForeColor = Color.Red; } } private void OnThumbnailClick(object sender, EventArgs e) { ThumbnailClicked?.Invoke(this, EventArgs.Empty); } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); // Draw selection border if selected if (_isSelected) { using (var pen = new Pen(Color.DodgerBlue, BorderWidth)) { var rect = new Rectangle( BorderWidth / 2, BorderWidth / 2, Width - BorderWidth, Height - BorderWidth ); e.Graphics.DrawRectangle(pen, rect); } } } protected override void Dispose(bool disposing) { if (disposing) { // Dispose the image to free memory _pictureBox?.Image?.Dispose(); _pictureBox?.Dispose(); _label?.Dispose(); } base.Dispose(disposing); } } }