Files
atvstdla dc66158497 Add QRValidation project to repository
- Added QRValidation vision control system
- Includes CapCleaningControl UI components
- WebSocket-based barcode validation system
- Support for Crevis PLC integration
- Test projects for PLC emulator, motion, IO panel, and Modbus

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-02 11:38:38 +09:00

344 lines
15 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
namespace UIControl
{
public partial class Unloader : UserControl
{
public Boolean bRemakeRect = true;
public CPort[] ports;
public Font Font_Alert { get; set; }
public Font Font_SIDLIST { get; set; }
public Font Font_Sign { get; set; }
private Color _portback = Color.FromArgb(32, 32, 32);
public Color arPortBack { get { return _portback; } set { _portback = value; this.Invalidate(); } }
private Color _titleback = Color.DeepSkyBlue;
public Color arTitleBack { get { return _titleback; } set { _titleback = value; this.Invalidate(); } }
public Boolean arStop { get; set; }
public Boolean arBusy { get; set; }
public Boolean debugMode { get; set; }
double port_width, port_height, space_width;
public Unloader()
{
InitializeComponent();
// Set Optimized Double Buffer to reduce flickering
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
this.SetStyle(ControlStyles.ContainerControl, false);
this.SetStyle(ControlStyles.Selectable, true);
// Redraw when resized
this.SetStyle(ControlStyles.ResizeRedraw, true);
Font_SIDLIST = new Font("Consolas", 30, FontStyle.Bold);
this.Padding = new Padding(5, 5, 5, 5);
this.Font_Sign = new Font("Consolas", 15, FontStyle.Bold);
this.Font_Alert = new Font("Consolas", 30, FontStyle.Bold);
}
protected override void OnResize(EventArgs e)
{
bRemakeRect = true;
Invalidate();
// base.OnResize(e);
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (ports == null || ports.Length == 0)
{
this.ports = new CPort[]
{
new CPort(){ cartSize=7, cartState = 1, Mode="USER", portName="#11", portNo=1 },
new CPort(){ cartSize=7, cartState = 1, Mode="USER", portName="#21", portNo=2 },
new CPort(){ cartSize=13, cartState = 0, Mode="USER", portName="#12", portNo=3 },
new CPort(){ cartSize=13, cartState = 2, Mode="USER", portName="#22", portNo=4 },
};
this.ports[0].reelSID.Add(new CPortData("012345678",30,100,"릴#6"));
//e.Graphics.DrawString("PORT가 설정되지 않았습니다", this.Font, Brushes.White, DisplayRectangle,
// new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });
//return;
}
//Set Optimized Double Buffer to reduce flickering
e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
e.Graphics.InterpolationMode = InterpolationMode.High;
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
//e.Graphics.DrawString(DisplayRectangle.ToString(), this.Font, Brushes.White, 1, 1);
//포트영역생성
if (bRemakeRect)
{
space_width = 10;
int row = 2;
int col = 2;
port_width = (DisplayRectangle.Width - (col - 1) * space_width) / 2f;
port_height = (DisplayRectangle.Height - (row - 1) * space_width) / 2f;
//space_width = (DisplayRectangle.Width - (port_width * 2.0)) / 3.0;
//space_height = (DisplayRectangle.Height - (port_height * 2.0)) / 3.0;
var signSize = e.Graphics.MeasureString("13\"", this.Font_Sign);
var titlesize = e.Graphics.MeasureString("1.01234567890", this.Font);
var idx = 0;
for (int c = 0; c < col; c++)
{
for (int r = 0; r < row; r++)
{
ports[idx].rect = new Rectangle(
(int)(DisplayRectangle.Left + (c * space_width) + (c * port_width)),
(int)(DisplayRectangle.Top + (r * space_width) + (r * port_height)),
(int)port_width,
(int)port_height);
ports[idx].rect_signL = new Rectangle(
(int)(DisplayRectangle.Left + (c * space_width) + (c * port_width)),
(int)(DisplayRectangle.Top + (r * space_width) + (r * port_height)),
(int)(signSize.Width * 1.05f),
(int)(signSize.Height * 1.05f));
ports[idx].rect_signR = new Rectangle(
(int)(ports[idx].rect.Right - ports[idx].rect_signL.Width),
ports[idx].rect_signL.Top,
ports[idx].rect_signL.Width,
ports[idx].rect_signL.Height);
ports[idx].rect_title = new Rectangle(
(int)(ports[idx].rect.Left),
(int)(ports[idx].rect.Top), //Bottom - (titlesize.Height * 1.2f)),
ports[idx].rect.Width,
(int)(signSize.Height * 1.05f));
ports[idx].rect_count = new Rectangle(
ports[idx].rect.Left + 2,
ports[idx].rect_title.Bottom + 2,
ports[idx].rect.Width - 4,
ports[idx].rect.Height - ports[idx].rect_title.Height - 4
);
idx += 1;
}
}
bRemakeRect = false;
}
//포트그리기 (총 4개의 포트가 있다)
var sfCenter = new StringFormat
{
Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Center,
};
var sfLeft = new StringFormat
{
Alignment = StringAlignment.Near,
LineAlignment = StringAlignment.Center,
};
foreach (var port in ports)
{
//배경영역 칠하기
e.Graphics.FillRectangle(new SolidBrush(this._portback), port.rect);
if (port.Mode == "USER")
e.Graphics.FillRectangle(new SolidBrush(Color.SkyBlue), port.rect_title);
else
e.Graphics.FillRectangle(new SolidBrush(this._titleback), port.rect_title);
//글자영역 칠하기
if(port.cartSize ==13)
e.Graphics.FillRectangle(Brushes.Gold, port.rect_signL);
else
e.Graphics.FillRectangle(Brushes.WhiteSmoke, port.rect_signL);
e.Graphics.FillRectangle(Brushes.WhiteSmoke, port.rect_signR);
var portSize = port.cartSize == 0 ? "--" : port.cartSize + "\"";
e.Graphics.DrawString(portSize, this.Font_Sign, Brushes.Black, port.rect_signL, sfCenter);
//sign R 에는 카운트를 넣는다
//var portStat = port.cartState == 0 ? "STP" : (port.cartState == 1 ? "RDY" : "MAX");
var portStatBG = port.cartState == 0 ? Color.Gray : (port.cartState == 1 ? Color.Green : Color.Tomato);
e.Graphics.DrawString(port.reelCount.ToString(), this.Font_Sign, new SolidBrush(portStatBG), port.rect_signR, sfCenter);
//타이틀 글자
var title = "[ " + port.portNo.ToString() + " ]";
if (string.IsNullOrEmpty(port.portName) == false && port.portName != port.portNo.ToString())
{
title = "[" + port.portNo.ToString() + ":" + port.portName + "]";
}
//if (port.Mode == "DISABLE") title += " (사용안함)";
//else if (port.Mode == "EXIT") title += " (배출전용)";
//if (port.Mode == "USER") title = "* " + port.portNo.ToString() + " *";
//else if (port.Mode == "DISABLE") title = "# " + port.portNo.ToString() + " #";
//else
//{
//if (port.reelSID.Count == 0) title += " (할당안됨)";
//else if (port.reelSID.Count == 1) title += " " + port.reelSID[0];
//else title += " " + port.reelSID[0] + "(" + (port.reelSID.Count - 1).ToString() + ")";
//}
if (string.IsNullOrEmpty(title) == false)
{
e.Graphics.DrawString(title, Font_Sign, new SolidBrush(Color.Black), port.rect_title, sfCenter);
}
//SID목록 가져온다
//port.reelSID.Clear();
//port.reelSID.AddRange(new CPortData[] {
// new CPortData("0123456789A",1,10),
// new CPortData("0123456789B",2,10),
// new CPortData("0123456789C",3,10),
// new CPortData("0123456789D",4,10)
//});
Color cntColor = ForeColor;
string SidList = string.Empty;
if (port.Mode == "USER") SidList = "";// cntColor = Color.FromArgb(50, 50, 50);
foreach (var sid in port.reelSID)
{
if (sid.Active == false) continue; //비활성화된것은 표시하지 않는다
if (string.IsNullOrEmpty(SidList) == false) SidList += "\n";
SidList += string.Format(" {0} ({1}/{2})→{3}", sid.sid, sid.qty, sid.kpc,sid.towername);
}
e.Graphics.DrawString(SidList,
Font_SIDLIST,
new SolidBrush(cntColor),
port.rect_count, new StringFormat { Alignment = StringAlignment.Near, LineAlignment = StringAlignment.Near });
//e.Graphics.DrawRect(port.rect_count, Color.DarkBlue, 5);
///테두리
e.Graphics.DrawRectangle(Pens.Gray, port.rect);
using (Font fsta = new Font("맑은 고딕", 25f, FontStyle.Regular))
{
//장비상태는 추가로 표시해준다.
//STOP혹은 MAX라면 별도 표기한다. //미사용도 마찬가지
if (port.Mode == "DISABLE")
{
using (var sb = new SolidBrush(Color.FromArgb(220, Color.White)))
{
e.Graphics.FillRectangle(sb, port.rect_count);
}
if (string.IsNullOrEmpty(port.portName) == false && port.portName != port.portNo.ToString())
e.Graphics.DrawString(title + "\nDISABLE", fsta, new SolidBrush(Color.Black), port.rect_count, sfCenter);
else e.Graphics.DrawString(title + "\nDISABLE", fsta, new SolidBrush(Color.Black), port.rect_count, sfCenter);
}
else if (port.cartState == 0)
{
//stop
using (var sb = new SolidBrush(Color.FromArgb(220, Color.Yellow)))
{
e.Graphics.FillRectangle(sb, port.rect_count);
}
if (string.IsNullOrEmpty(port.portName) == false && port.portName != port.portNo.ToString())
e.Graphics.DrawString(title + "\nSTOP", fsta, new SolidBrush(Color.Black), port.rect_count, sfCenter);
else
e.Graphics.DrawString(title + "\nSTOP", fsta, new SolidBrush(Color.Black), port.rect_count, sfCenter);
}
else if (port.cartState == 2)
{
//max
using (var sb = new SolidBrush(Color.FromArgb(220, Color.Red)))
{
e.Graphics.FillRectangle(sb, port.rect_count);
}
if (string.IsNullOrEmpty(port.portName) == false && port.portName != port.portNo.ToString())
e.Graphics.DrawString(title + "\nFULL", fsta, new SolidBrush(Color.Black), port.rect_count, sfCenter);
else
e.Graphics.DrawString(title + "\nFULL", fsta, new SolidBrush(Color.White), port.rect_count, sfCenter);
}
}
//var portStat = port.cartState == 0 ? "STP" : (port.cartState == 1 ? "RDY" : "MAX");
//var portStatBG = port.cartState == 0 ? Color.Gray : (port.cartState == 1 ? Color.Green : Color.Tomato);
//e.Graphics.DrawString(portStat, this.Font_Sign, new SolidBrush(portStatBG), port.rect_signR, sfCenter);
}
if (this.arStop)
{
e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(240, Color.Black)), DisplayRectangle);
e.Graphics.DrawString("STOP", this.Font_Alert, Brushes.Orange, DisplayRectangle, sfCenter);
}
else if (this.arBusy)
{
e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(240, Color.Black)), DisplayRectangle);
e.Graphics.DrawString("BUSY", this.Font_Alert, Brushes.Aqua, DisplayRectangle, sfCenter);
}
if (debugMode)
{
var sb = new System.Text.StringBuilder();
sb.AppendLine("unloader ctonrol");
sb.AppendLine(string.Format("port size {0}x{1}", port_width, port_height));
sb.AppendLine(string.Format("space size {0}x{1}", space_width, space_width));
sb.AppendLine(string.Format("display rect {0}", DisplayRectangle));
e.Graphics.DrawString(sb.ToString(), this.Font, Brushes.White, 10, 10);
}
//e.Graphics.DrawRectangle(Pens.White, DisplayRectangle);
sfCenter.Dispose();
sfLeft.Dispose();
}
public class ClickEventArgs : EventArgs
{
public int idx { get; set; }
public ClickEventArgs(int idx_)
{
this.idx = idx_;
}
}
public event EventHandler<ClickEventArgs> ItemClick;
protected override void OnMouseClick(MouseEventArgs e)
{
base.OnMouseClick(e);
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
var item = this.ports.Where(t => t.rect.Contains(e.Location)).FirstOrDefault();
if (item != null)
{
//이 영역을 클릭한것으로 한다
if (ItemClick != null)
ItemClick(this, new ClickEventArgs(item.idx));
}
}
}
}
}