| | |
| | | #include "stdafx.h" |
| | | #include "JobSlotGrid.h" |
| | | #include "ServoMemDC.h" |
| | | |
| | | #ifdef _DEBUG |
| | | #define new DEBUG_NEW |
| | |
| | | BEGIN_MESSAGE_MAP(CJobSlotGrid, CWnd) |
| | | ON_WM_PAINT() |
| | | ON_WM_ERASEBKGND() |
| | | ON_WM_MOUSEMOVE() |
| | | ON_WM_MOUSELEAVE() |
| | | ON_WM_LBUTTONDOWN() |
| | | ON_WM_LBUTTONUP() |
| | | END_MESSAGE_MAP() |
| | | |
| | | CJobSlotGrid::CJobSlotGrid() { |
| | |
| | | m_nRows = nRows; |
| | | m_nCols = nCols; |
| | | m_vSlotStatus.assign(nRows, std::vector<bool>(nCols, false)); |
| | | m_vSlotClickable.assign(nRows, std::vector<bool>(nCols, false)); |
| | | |
| | | // 初始化文本数组 |
| | | m_vSlotText.assign(nRows, std::vector<CString>(nCols)); |
| | |
| | | Invalidate(); |
| | | } |
| | | |
| | | void CJobSlotGrid::SetSlotClickable(int nRow, int nCol, bool bClickable) |
| | | { |
| | | if (nRow >= 0 && nRow < m_nRows && nCol >= 0 && nCol < m_nCols) { |
| | | m_vSlotClickable[nRow][nCol] = bClickable; |
| | | } |
| | | } |
| | | |
| | | bool CJobSlotGrid::IsSlotClickable(int nRow, int nCol) const |
| | | { |
| | | if (nRow >= 0 && nRow < m_nRows && nCol >= 0 && nCol < m_nCols) { |
| | | return m_vSlotClickable[nRow][nCol]; |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | void CJobSlotGrid::SetSlotClickCallback(SlotClickCallback fnCallback) |
| | | { |
| | | m_fnSlotClickCallback = fnCallback; |
| | | } |
| | | |
| | | BOOL CJobSlotGrid::OnEraseBkgnd(CDC* pDC) { |
| | | return TRUE; |
| | | } |
| | | |
| | | void CJobSlotGrid::OnMouseMove(UINT nFlags, CPoint point) |
| | | { |
| | | TRACKMOUSEEVENT tme = { sizeof(TRACKMOUSEEVENT), TME_LEAVE, m_hWnd }; |
| | | ::TrackMouseEvent(&tme); |
| | | |
| | | CRect rect; |
| | | GetClientRect(&rect); |
| | | int nCellWidth = rect.Width() / m_nCols; |
| | | int nCellHeight = rect.Height() / m_nRows; |
| | | |
| | | int nCol = point.x / nCellWidth; |
| | | int nRow = point.y / nCellHeight; |
| | | |
| | | if (nRow != m_ptHover.y || nCol != m_ptHover.x) { |
| | | m_ptHover = CPoint(nCol, nRow); |
| | | Invalidate(); |
| | | } |
| | | |
| | | CWnd::OnMouseMove(nFlags, point); |
| | | } |
| | | |
| | | void CJobSlotGrid::OnMouseLeave() |
| | | { |
| | | m_ptHover = CPoint(-1, -1); |
| | | Invalidate(); |
| | | |
| | | CWnd::OnMouseLeave(); |
| | | } |
| | | |
| | | void CJobSlotGrid::OnLButtonDown(UINT nFlags, CPoint point) |
| | | { |
| | | m_bLButtonDown = true; |
| | | Invalidate(); |
| | | |
| | | CWnd::OnLButtonDown(nFlags, point); |
| | | } |
| | | |
| | | void CJobSlotGrid::OnLButtonUp(UINT nFlags, CPoint point) |
| | | { |
| | | m_bLButtonDown = false; |
| | | Invalidate(); |
| | | |
| | | // 保持原有逻辑不变 |
| | | CRect rect; |
| | | GetClientRect(&rect); |
| | | int nCellWidth = rect.Width() / m_nCols; |
| | | int nCellHeight = rect.Height() / m_nRows; |
| | | |
| | | int nCol = point.x / nCellWidth; |
| | | int nRow = point.y / nCellHeight; |
| | | |
| | | if (IsSlotClickable(nRow, nCol)) { |
| | | if (m_fnSlotClickCallback) { |
| | | m_fnSlotClickCallback(nRow, nCol); |
| | | } |
| | | } |
| | | |
| | | CWnd::OnLButtonUp(nFlags, point); |
| | | } |
| | | |
| | | void CJobSlotGrid::OnPaint() { |
| | | CPaintDC dc(this); |
| | | DrawGrid(&dc); |
| | | CServoMemDC memDC(&dc); |
| | | DrawGrid(&memDC); |
| | | } |
| | | |
| | | void CJobSlotGrid::DrawGrid(CDC* pDC) |
| | | { |
| | | CRect rect; |
| | | GetClientRect(&rect); |
| | | pDC->FillSolidRect(&rect, ::GetSysColor(COLOR_3DFACE)); // 安全背景色,仅内存绘制 |
| | | |
| | | if (m_nCols == 0 || m_nRows == 0) { |
| | | return; |
| | | } |
| | | |
| | | // 计算格子尺寸 |
| | | int nCellWidth = rect.Width() / m_nCols; |
| | | int nCellHeight = rect.Height() / m_nRows; |
| | | |
| | | // 字体设置 |
| | | CFont* pOldFont = pDC->SelectObject(&m_fontText); |
| | | pDC->SetBkMode(TRANSPARENT); |
| | | pDC->SetTextColor(RGB(0, 0, 0)); |
| | | |
| | | // 定义颜色常量 |
| | | constexpr COLORREF COLOR_HOVER = RGB(200, 230, 255); |
| | | constexpr COLORREF COLOR_CLICK = RGB(0, 120, 215); |
| | | |
| | | for (int i = 0; i < m_nRows; ++i) { |
| | | for (int j = 0; j < m_nCols; ++j) { |
| | | CRect cellRect(j * nCellWidth, i * nCellHeight, (j + 1) * nCellWidth, (i + 1) * nCellHeight); |
| | | |
| | | // 背景 |
| | | CBrush* pBrush = m_vSlotStatus[i][j] ? &m_brushHasJob : &m_brushNoJob; |
| | | pDC->FillRect(&cellRect, pBrush); |
| | | // 判断状态:悬停 / 按下 |
| | | bool bIsHover = (m_ptHover.x == j && m_ptHover.y == i); |
| | | bool bIsClicking = bIsHover && m_bLButtonDown; |
| | | |
| | | // 边框 |
| | | // 选择填充颜色 |
| | | COLORREF fillColor = m_vSlotStatus[i][j] ? m_colorHasJob : m_colorNoJob; |
| | | if (IsSlotClickable(i, j)) { |
| | | if (bIsClicking) { |
| | | fillColor = COLOR_CLICK; |
| | | } |
| | | else if (bIsHover) { |
| | | fillColor = COLOR_HOVER; |
| | | } |
| | | } |
| | | |
| | | // 绘制背景(高效替代 CBrush) |
| | | pDC->FillSolidRect(&cellRect, fillColor); |
| | | |
| | | // 绘制边框 |
| | | pDC->DrawEdge(&cellRect, EDGE_SUNKEN, BF_RECT); |
| | | |
| | | // 文字(居中) |
| | | pDC->SetBkMode(TRANSPARENT); |
| | | pDC->SetTextColor(RGB(0, 0, 0)); |
| | | pDC->DrawText(m_vSlotText[i][j], &cellRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); |
| | | // 如果是可点击格子,在左上角画一个小圆点 |
| | | if (IsSlotClickable(i, j)) { |
| | | constexpr int DOT_RADIUS = 3; |
| | | int cx = cellRect.left + 5; |
| | | int cy = cellRect.top + 5; |
| | | |
| | | // 保存旧笔和刷子 |
| | | CBrush brushDot(RGB(0, 120, 215)); |
| | | CBrush* pOldBrush = pDC->SelectObject(&brushDot); |
| | | CPen penDot(PS_SOLID, 1, RGB(0, 120, 215)); |
| | | CPen* pOldPen = pDC->SelectObject(&penDot); |
| | | |
| | | // 绘制圆点 |
| | | pDC->Ellipse(cx - DOT_RADIUS, cy - DOT_RADIUS, cx + DOT_RADIUS, cy + DOT_RADIUS); |
| | | |
| | | // 恢复 |
| | | pDC->SelectObject(pOldBrush); |
| | | pDC->SelectObject(pOldPen); |
| | | } |
| | | |
| | | // 获取文字(安全) |
| | | CString strText; |
| | | if (i < m_vSlotText.size() && j < m_vSlotText[i].size()) { |
| | | strText = m_vSlotText[i][j]; |
| | | } |
| | | |
| | | if (!strText.IsEmpty()) { |
| | | // 先计算文字高度(支持换行) |
| | | CRect calcRect = cellRect; |
| | | pDC->DrawText(strText, &calcRect, DT_CENTER | DT_WORDBREAK | DT_NOPREFIX | DT_CALCRECT); |
| | | |
| | | // 重新设定居中绘制区域 |
| | | CRect textRect = cellRect; |
| | | textRect.top += (cellRect.Height() - calcRect.Height()) / 2; |
| | | |
| | | // 实际绘制文字 |
| | | pDC->DrawText(strText, &textRect, DT_CENTER | DT_WORDBREAK | DT_NOPREFIX); |
| | | } |
| | | } |
| | | } |
| | | |
| | | pDC->SelectObject(pOldFont); |
| | | } |
| | | } |