// PortConfigurationDlg.cpp: 实现文件
|
//
|
|
#include "stdafx.h"
|
#include "Servo.h"
|
#include "afxdialogex.h"
|
#include "PortConfigurationDlg.h"
|
#include "NewCellTypes/GridCellCheck.h"
|
#include "NewCellTypes/GridCellCombo.h"
|
#include "NewCellTypes/GridCellNumeric.h"
|
#include "RecipeManager.h"
|
#include "ServoCommo.h"
|
|
|
|
#define CHECKBOX_ALL_ID 0x1234
|
|
// CPortConfigurationDlg 对话框
|
|
IMPLEMENT_DYNAMIC(CPortConfigurationDlg, CDialogEx)
|
|
CPortConfigurationDlg::CPortConfigurationDlg(CWnd* pParent /*=nullptr*/)
|
: CDialogEx(IDD_DIALOG_PORT_CONFIGURATION, pParent)
|
{
|
// 初始化成员变量
|
m_pPort[0] = dynamic_cast<SERVO::CLoadPort*>(theApp.m_model.m_master.getEquipment(EQ_ID_LOADPORT1));
|
m_pPort[1] = dynamic_cast<SERVO::CLoadPort*>(theApp.m_model.m_master.getEquipment(EQ_ID_LOADPORT2));
|
m_pPort[2] = dynamic_cast<SERVO::CLoadPort*>(theApp.m_model.m_master.getEquipment(EQ_ID_LOADPORT3));
|
m_pPort[3] = dynamic_cast<SERVO::CLoadPort*>(theApp.m_model.m_master.getEquipment(EQ_ID_LOADPORT4));
|
m_nCurSelPort = -1;
|
m_pCheckBox = nullptr;
|
m_bCheckedAll = FALSE;
|
}
|
|
CPortConfigurationDlg::~CPortConfigurationDlg()
|
{
|
}
|
|
void CPortConfigurationDlg::setCurSelPort(int sel)
|
{
|
m_nCurSelPort = sel;
|
}
|
|
int CPortConfigurationDlg::GetLoadPortEqID(const std::string& strPortName)
|
{
|
if (strPortName == "Port 1") return EQ_ID_LOADPORT1;
|
if (strPortName == "Port 2") return EQ_ID_LOADPORT2;
|
if (strPortName == "Port 3") return EQ_ID_LOADPORT3;
|
if (strPortName == "Port 4") return EQ_ID_LOADPORT4;
|
return -1; // 未知端口
|
}
|
|
void CPortConfigurationDlg::LoadPortConfigToUI(SERVO::CLoadPort* pPort)
|
{
|
if (!pPort) {
|
return;
|
}
|
|
CStringArray permissions;
|
permissions.Add(_T("G1"));
|
permissions.Add(_T("G2"));
|
|
SetDlgItemText(IDC_EDIT_LOTID, "");
|
SetDlgItemText(IDC_EDIT_PRODUCTID, "");
|
SetDlgItemText(IDC_EDIT_OPERATIONID, "");
|
m_comboMaterialsType.SetCurSel(0);
|
|
bool bJobInfoSet = false;
|
for (int i = 0; i < SLOT_MAX; ++i) {
|
SERVO::CSlot* pSlot = pPort->getSlot(i);
|
if (!pSlot) {
|
continue;
|
}
|
|
// 设置 Panel ID 和勾选框
|
SERVO::CGlass* pGlass = dynamic_cast<SERVO::CGlass*>(pSlot->getContext());
|
SERVO::CJobDataS* pJobDataS = pGlass->getJobDataS();
|
int nRow = i + 1;
|
if (pGlass != nullptr && pJobDataS != nullptr) {
|
m_wndGrid.SetItemState(nRow, 0, GVIS_READONLY);
|
m_wndGrid.SetItemText(nRow, 0, pSlot->getName().c_str());
|
m_wndGrid.SetCellType(nRow, 1, RUNTIME_CLASS(CGridCellCheck));
|
CGridCellCheck* pCheck = dynamic_cast<CGridCellCheck*>(m_wndGrid.GetCell(nRow, 1));
|
ASSERT(pCheck);
|
pCheck->SetCheck(pGlass->isScheduledForProcessing());
|
pCheck->SetText(pGlass->getID().c_str());
|
|
if (m_wndGrid.SetCellType(nRow, 2, RUNTIME_CLASS(CGridCellCombo))) {
|
CGridCellCombo* pCell = static_cast<CGridCellCombo*>(m_wndGrid.GetCell(nRow, 2));
|
pCell->SetOptions(permissions);
|
pCell->SetStyle(CBS_DROPDOWNLIST);
|
|
int nMaterialsType = pJobDataS->getMaterialsType() - 1;
|
if (nMaterialsType < 0 || nMaterialsType > 2) {
|
nMaterialsType = 0;
|
}
|
m_wndGrid.SetItemText(nRow, 2, permissions.GetAt(nMaterialsType));
|
}
|
}
|
m_wndGrid.SetItemData(nRow, 0, (LPARAM)pGlass);
|
|
// 回填 Job 信息(只取第一个有效 Glass)
|
if (!bJobInfoSet && pGlass) {
|
SERVO::CJobDataS* pJS = pGlass->getJobDataS();
|
if (pJS) {
|
SetDlgItemText(IDC_EDIT_LOTID, CString(pJS->getLotId().c_str()));
|
SetDlgItemText(IDC_EDIT_PRODUCTID, CString(pJS->getProductId().c_str()));
|
SetDlgItemText(IDC_EDIT_OPERATIONID, CString(pJS->getOperationId().c_str()));
|
m_comboMaterialsType.SetCurSel(pJS->getMaterialsType() - 1);
|
bJobInfoSet = true;
|
}
|
}
|
}
|
m_pCheckBox->SetCheck(IsCheckedAll() ? BST_CHECKED : BST_UNCHECKED);
|
}
|
|
void CPortConfigurationDlg::InitGrid()
|
{
|
if (m_wndGrid.GetSafeHwnd() == NULL) {
|
return;
|
}
|
|
const int nCols = 3;
|
const int nFixRows = 1;
|
const int nRows = SLOT_MAX + 1; // 存在表头,所以 +1
|
|
int nColIdx = 0;
|
m_wndGrid.DeleteAllItems();
|
m_wndGrid.SetVirtualMode(FALSE);
|
|
// 设置样式颜色
|
m_wndGrid.GetDefaultCell(TRUE, FALSE)->SetBackClr(g_nGridFixCellColor);
|
m_wndGrid.GetDefaultCell(FALSE, TRUE)->SetBackClr(g_nGridFixCellColor);
|
m_wndGrid.GetDefaultCell(FALSE, FALSE)->SetBackClr(g_nGridCellColor);
|
m_wndGrid.SetFixedTextColor(g_nGridFixFontColor);
|
|
// 行列数量
|
m_wndGrid.SetRowCount(nRows);
|
m_wndGrid.SetColumnCount(nCols);
|
m_wndGrid.SetFixedRowCount(nFixRows);
|
m_wndGrid.SetFixedColumnCount(0);
|
|
// 设置列宽
|
m_wndGrid.SetColumnWidth(nColIdx, 50);
|
m_wndGrid.SetItemText(0, nColIdx++, _T("Slot ID"));
|
m_wndGrid.SetColumnWidth(nColIdx, 60);
|
m_wndGrid.SetItemText(0, nColIdx++, _T("Glass ID"));
|
m_wndGrid.SetColumnWidth(nColIdx, 60);
|
m_wndGrid.SetItemText(0, nColIdx++, _T("物料类型"));
|
|
|
// 设置行为样式
|
m_wndGrid.SetFixedRowSelection(FALSE);
|
m_wndGrid.SetFixedColumnSelection(FALSE);
|
m_wndGrid.SetEditable(TRUE);
|
m_wndGrid.SetRowResize(FALSE);
|
m_wndGrid.SetColumnResize(FALSE);
|
m_wndGrid.SetListMode(TRUE);
|
m_wndGrid.EnableSelection(TRUE);
|
m_wndGrid.SetSingleRowSelection(TRUE);
|
m_wndGrid.ExpandColumnsToFit(TRUE);
|
m_wndGrid.ExpandLastColumn();
|
|
// 自动计算并设置每行高度
|
CRect rcClient;
|
m_wndGrid.GetClientRect(&rcClient);
|
int nAvailableHeight = rcClient.Height();
|
int nEachRowHeight = max(24, nAvailableHeight / nRows);
|
|
for (int i = 0; i < nRows; ++i) {
|
m_wndGrid.SetRowHeight(i, nEachRowHeight);
|
}
|
|
CRect rect;
|
BOOL bOK = m_wndGrid.GetCellRect(0, 1, rect);
|
m_pCheckBox = new CCustomCheckBox();
|
m_pCheckBox->Create(_T("选择所有"),
|
WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX, // 自动勾选
|
CRect(0, 0, 150, 32), &m_wndGrid, CHECKBOX_ALL_ID);
|
m_pCheckBox->SetFont(GetFont());
|
m_pCheckBox->MoveWindow(rect.left + 5, rect.top + 3, 150, rect.Height() - 6);
|
m_pCheckBox->SetBackgroundColor(g_nGridFixCellColor);
|
m_pCheckBox->SetNotifyHwnd(GetSafeHwnd());
|
}
|
|
void CPortConfigurationDlg::DoDataExchange(CDataExchange* pDX)
|
{
|
CDialogEx::DoDataExchange(pDX);
|
DDX_Control(pDX, IDC_GRID_PANEL_RECIPE, m_wndGrid);
|
DDX_Control(pDX, IDC_COMBO_PORT, m_comboPort);
|
DDX_Control(pDX, IDC_COMBO_RECIPE, m_comboRecipe);
|
DDX_Control(pDX, IDC_COMBO_MATERIALS_TYPE, m_comboMaterialsType);
|
}
|
|
|
BEGIN_MESSAGE_MAP(CPortConfigurationDlg, CDialogEx)
|
ON_CBN_SELCHANGE(IDC_COMBO_PORT, &CPortConfigurationDlg::OnSelchangeComboPort)
|
ON_BN_CLICKED(IDC_BUTTON_APPLY, &CPortConfigurationDlg::OnBnClickedButtonApply)
|
ON_MESSAGE(WM_CHECKBOX_STATE_CHANGED, &CPortConfigurationDlg::OnCheckAllClicked)
|
ON_WM_DESTROY()
|
ON_BN_CLICKED(IDC_BUTTON_PROCESS_START, &CPortConfigurationDlg::OnBnClickedButtonProcessStart)
|
ON_BN_CLICKED(IDC_BUTTON_PROCESS_CANCEL, &CPortConfigurationDlg::OnBnClickedButtonProcessCancel)
|
END_MESSAGE_MAP()
|
|
|
// CPortConfigurationDlg 消息处理程序
|
|
BOOL CPortConfigurationDlg::OnInitDialog()
|
{
|
CDialogEx::OnInitDialog();
|
|
// TODO: 在此添加额外的初始化
|
// 初始化端口下拉框内容
|
CString ports[] = { _T("Port 1"), _T("Port 2"), _T("Port 3"), _T("Port 4") };
|
for (const auto& item : ports) {
|
m_comboPort.AddString(item);
|
}
|
if (0 <= m_nCurSelPort && m_nCurSelPort <= 3) {
|
m_comboPort.SetCurSel(m_nCurSelPort);
|
m_comboPort.EnableWindow(FALSE);
|
}
|
else {
|
m_comboPort.SetCurSel(0);
|
}
|
|
// 初始化配方下拉框内容
|
std::vector<std::string> vecRecipe = RecipeManager::getInstance().getAllPPID();
|
for (const auto& recipe : vecRecipe) {
|
m_comboRecipe.AddString(CString(recipe.c_str()));
|
}
|
m_comboRecipe.SetCurSel(0); // 默认选择第一个配方
|
|
// 初始化物料类型下拉框内容
|
CString materialTypes[] = { _T("G1"), _T("G2"), _T("G1+G2") };
|
for (const auto& item : materialTypes) {
|
m_comboMaterialsType.AddString(item);
|
}
|
m_comboMaterialsType.SetCurSel(0); // 默认选择第一个物料类型
|
m_comboMaterialsType.EnableWindow(FALSE);
|
InitGrid();
|
|
LoadPortConfigToUI(m_pPort[0]); // 默认加载第一个端口的配置
|
|
// 设置对话框标题
|
BOOL bAutoPopup = 0 <= m_nCurSelPort && m_nCurSelPort <= 3;
|
if (bAutoPopup) {
|
CString strTitle;
|
strTitle.Format(_T("%s Configuration"), ports[m_nCurSelPort]);
|
SetWindowText(strTitle);
|
}
|
else {
|
SetWindowText(_T("Port Configuration"));
|
}
|
|
|
// Porcess Start / Process Cancel 按钮状态
|
GetDlgItem(IDC_BUTTON_PROCESS_START)->EnableWindow(FALSE);
|
GetDlgItem(IDC_BUTTON_PROCESS_CANCEL)->EnableWindow(FALSE);
|
|
return TRUE; // return TRUE unless you set the focus to a control
|
// 异常: OCX 属性页应返回 FALSE
|
}
|
|
void CPortConfigurationDlg::OnSelchangeComboPort()
|
{
|
// TODO: 在此添加控件通知处理程序代码
|
int selPort = m_comboPort.GetCurSel();
|
if (selPort < 0 || selPort >= 4) {
|
return; // 无效选择
|
}
|
|
// 加载选中端口的配置到 UI
|
for (int i = 1; i <= 8; i++) {
|
m_wndGrid.SetItemText(i, 0, "");
|
m_wndGrid.SetItemText(i, 1, "");
|
m_wndGrid.SetCellType(i, 1, RUNTIME_CLASS(CGridCellNumeric));
|
}
|
m_wndGrid.Invalidate();
|
LoadPortConfigToUI(m_pPort[selPort]);
|
}
|
|
void CPortConfigurationDlg::OnBnClickedButtonApply()
|
{
|
// TODO: 在此添加控件通知处理程序代码
|
SERVO::PortConfig config;
|
|
// 获取 Port 名称
|
int selPort = m_comboPort.GetCurSel();
|
if (selPort != CB_ERR) {
|
CString str;
|
m_comboPort.GetLBText(selPort, str);
|
config.strPortName = CT2A(str.GetString());
|
}
|
|
// 获取 Recipe 名称
|
int selRecipe = m_comboRecipe.GetCurSel();
|
if (selRecipe != CB_ERR) {
|
CString str;
|
m_comboRecipe.GetLBText(selRecipe, str);
|
config.strRecipe = CT2A(str.GetString());
|
}
|
|
// 获取 Material Type 索引(索引从 0 开始,对应枚举从 1 开始)
|
//int selMaterial = m_comboMaterialsType.GetCurSel();
|
//if (selMaterial != CB_ERR) {
|
// config.nMaterialType = selMaterial + 1;
|
//}
|
//else {
|
// AfxMessageBox(_T("Please select a material type!"));
|
// return;
|
//}
|
|
// 获取 Lot ID / Product ID / Operation ID
|
CString strText;
|
GetDlgItemText(IDC_EDIT_LOTID, strText);
|
config.strLotID = CT2A(strText.GetString());
|
if (config.strLotID.empty()) {
|
AfxMessageBox(_T("Lot ID cannot be empty!"));
|
return;
|
}
|
|
GetDlgItemText(IDC_EDIT_PRODUCTID, strText);
|
config.strProductID = CT2A(strText.GetString());
|
if (config.strProductID.empty()) {
|
AfxMessageBox(_T("Product ID cannot be empty!"));
|
return;
|
}
|
|
GetDlgItemText(IDC_EDIT_OPERATIONID, strText);
|
config.strOperationID = CT2A(strText.GetString());
|
if (config.strOperationID.empty()) {
|
AfxMessageBox(_T("Operation ID cannot be empty!"));
|
return;
|
}
|
|
// 获取 Grid 表格中 Slot 状态(第1~8行)
|
for (int i = 1; i <= SLOT_MAX; ++i) {
|
SERVO::CGlass* pGlass = (SERVO::CGlass*)m_wndGrid.GetItemData(i, 0);
|
int nMaterialType = m_wndGrid.GetItemText(i, 2).CompareNoCase("G1") == 0 ? 1 : 2;
|
if (pGlass != nullptr) {
|
CGridCellCheck* pCheck = dynamic_cast<CGridCellCheck*>(m_wndGrid.GetCell(i, 1));
|
CGridCellCombo* pCombo = dynamic_cast<CGridCellCombo*>(m_wndGrid.GetCell(i, 2));
|
ASSERT(pCheck && pCombo);
|
pGlass->setScheduledForProcessing(pCheck->GetCheck());
|
pGlass->setType(static_cast<SERVO::MaterialsType>(nMaterialType));
|
|
SERVO::CJobDataS* pJobDataS = pGlass->getJobDataS();
|
pJobDataS->setLotId(config.strLotID.c_str());
|
pJobDataS->setProductId(config.strProductID.c_str());
|
pJobDataS->setOperationId(config.strOperationID.c_str());
|
pJobDataS->setMaterialsType(nMaterialType);
|
|
RecipeInfo stRecipeInfo = RecipeManager::getInstance().getRecipeByPPID(config.strRecipe);
|
std::vector<DeviceRecipe> vecRecipeInfo = stRecipeInfo.vecDeviceList;
|
|
for (const auto& info : vecRecipeInfo) {
|
const std::string& name = info.strDeviceName;
|
short nRecipeID = (short)info.nRecipeID;
|
|
if (name == EQ_NAME_EFEM) {
|
pJobDataS->setDeviceRecipeId(0, nRecipeID);
|
}
|
else if (name == EQ_NAME_BONDER1) {
|
pJobDataS->setDeviceRecipeId(1, nRecipeID);
|
}
|
else if (name == EQ_NAME_BONDER2) {
|
pJobDataS->setDeviceRecipeId(2, nRecipeID);
|
}
|
else if (name == EQ_NAME_BAKE_COOLING) {
|
pJobDataS->setDeviceRecipeId(3, nRecipeID);
|
}
|
else if (name == EQ_NAME_VACUUMBAKE) {
|
pJobDataS->setDeviceRecipeId(4, nRecipeID);
|
}
|
else if (name == EQ_NAME_MEASUREMENT) {
|
pJobDataS->setDeviceRecipeId(5, nRecipeID);
|
}
|
}
|
}
|
}
|
|
GetDlgItem(IDC_BUTTON_PROCESS_START)->EnableWindow(TRUE);
|
GetDlgItem(IDC_BUTTON_PROCESS_CANCEL)->EnableWindow(TRUE);
|
}
|
|
void CPortConfigurationDlg::OnDestroy()
|
{
|
CDialogEx::OnDestroy();
|
|
if (m_pCheckBox != nullptr) {
|
m_pCheckBox->DestroyWindow();
|
delete m_pCheckBox;
|
m_pCheckBox = nullptr;
|
}
|
}
|
|
LRESULT CPortConfigurationDlg::OnCheckAllClicked(WPARAM wParam, LPARAM lParam)
|
{
|
UINT ctrlID = (UINT)wParam;
|
BOOL bChecked = (BOOL)lParam;
|
for (int i = 1; i <= SLOT_MAX; ++i) {
|
CGridCellCheck* pCheck = dynamic_cast<CGridCellCheck*>(m_wndGrid.GetCell(i, 1));
|
if (pCheck != nullptr) {
|
pCheck->SetCheck(bChecked);
|
}
|
}
|
|
|
return 0;
|
}
|
|
BOOL CPortConfigurationDlg::IsCheckedAll()
|
{
|
for (int i = 1; i <= SLOT_MAX; ++i) {
|
CGridCellCheck* pCheck = dynamic_cast<CGridCellCheck*>(m_wndGrid.GetCell(i, 1));
|
if (pCheck != nullptr) {
|
if (!pCheck->GetCheck()) return FALSE;
|
}
|
}
|
|
return TRUE;
|
}
|
|
void CPortConfigurationDlg::OnBnClickedButtonProcessStart()
|
{
|
int selPort = (0 <= m_nCurSelPort && m_nCurSelPort <= 3) ? m_nCurSelPort
|
: m_comboPort.GetCurSel();
|
if (selPort < 0 || selPort >= 4) return;
|
m_pPort[selPort]->sendCassetteCtrlCmd(CCC_PROCESS_START, nullptr, 0, 0, 0, nullptr, nullptr);
|
}
|
|
void CPortConfigurationDlg::OnBnClickedButtonProcessCancel()
|
{
|
int selPort = (0 <= m_nCurSelPort && m_nCurSelPort <= 3) ? m_nCurSelPort
|
: m_comboPort.GetCurSel();
|
if (selPort < 0 || selPort >= 4) return;
|
m_pPort[selPort]->sendCassetteCtrlCmd(CCC_PROCESS_CANCEL, nullptr, 0, 0, 0, nullptr, nullptr);
|
}
|