- 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>
344 lines
15 KiB
C#
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));
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|