LAPTOP-SNT8I5JK\Boounion
2025-07-11 2de4eb139c0cc595db761fedd822549384822fc9
SourceCode/Bond/Servo/JobSlotGrid.cpp
@@ -1,5 +1,6 @@
#include "stdafx.h"
#include "JobSlotGrid.h"
#include "ServoMemDC.h"
#ifdef _DEBUG
#define new DEBUG_NEW
@@ -10,6 +11,10 @@
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() {
@@ -48,6 +53,7 @@
    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));
@@ -130,41 +136,184 @@
    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);
}
}