// 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(theApp.m_model.m_master.getEquipment(EQ_ID_LOADPORT1)); m_pPort[1] = dynamic_cast(theApp.m_model.m_master.getEquipment(EQ_ID_LOADPORT2)); m_pPort[2] = dynamic_cast(theApp.m_model.m_master.getEquipment(EQ_ID_LOADPORT3)); m_pPort[3] = dynamic_cast(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; } 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(pSlot->getContext()); int nRow = i + 1; if (pGlass != 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(m_wndGrid.GetCell(nRow, 1)); ASSERT(pCheck); pCheck->SetCheck(pGlass->isScheduledForProcessing()); pCheck->SetText(pGlass->getID().c_str()); } 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 = 2; 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.SetFixedRowSelection(FALSE); m_wndGrid.SetFixedColumnSelection(FALSE); m_wndGrid.SetEditable(TRUE); m_wndGrid.SetRowResize(FALSE); m_wndGrid.SetColumnResize(TRUE); 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 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); // 默认选择第一个物料类型 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); if (pGlass != nullptr) { CGridCellCheck* pCheck = dynamic_cast(m_wndGrid.GetCell(i, 1)); ASSERT(pCheck); pGlass->setScheduledForProcessing(pCheck->GetCheck()); pGlass->setType(static_cast(config.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(config.nMaterialType); } } 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(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(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); }