#include "stdafx.h" #include "CCarrierSlotSelector.h" #define SAFE_PORT(p) ((p) >= 0 && (p) < (int)m_ports.size()) #define SAFE_SLOT(s) ((s) >= 0 && (s) < m_nSlots) #ifndef LVS_EX_DOUBLEBUFFER #define LVS_EX_DOUBLEBUFFER 0x00010000 #endif BEGIN_MESSAGE_MAP(CCarrierSlotSelector, CListCtrl) ON_WM_SHOWWINDOW() ON_WM_WINDOWPOSCHANGED() ON_WM_SIZE() ON_WM_ERASEBKGND() ON_WM_PAINT() // ¡ï ÐÂÔö ON_WM_LBUTTONDOWN() ON_WM_MOUSEMOVE() ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CCarrierSlotSelector::OnCustomDraw) END_MESSAGE_MAP() CCarrierSlotSelector::CCarrierSlotSelector() {} CCarrierSlotSelector::~CCarrierSlotSelector() { if ((HFONT)m_fntText) m_fntText.DeleteObject(); if ((HFONT)m_fntBold) m_fntBold.DeleteObject(); if ((HFONT)m_fntSmall) m_fntSmall.DeleteObject(); if ((HIMAGELIST)m_ilRowHeight) m_ilRowHeight.DeleteImageList(); } void CCarrierSlotSelector::PreSubclassWindow() { CListCtrl::PreSubclassWindow(); ModifyStyle(LVS_TYPEMASK, LVS_REPORT | LVS_SHOWSELALWAYS); ModifyStyle(LVS_OWNERDRAWFIXED | LVS_OWNERDATA, 0); DWORD ex = GetExtendedStyle(); ex |= LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER; ex &= ~LVS_EX_GRIDLINES; // ¹Ø±ÕÏµÍ³Íø¸ñ£¬¸Ä×Ô»æ SetExtendedStyle(ex); // ÈÃĬÈÏ»æÖÆÓÃÎÒÃǵĵ×É«£¬½øÒ»²½½µµÍ°×µ×»ú»á£¨¼´Ê¹ÄÄ´¦×ßÁËĬÈÏ·¾¶£© ListView_SetBkColor(m_hWnd, m_colBgNorm); ListView_SetTextBkColor(m_hWnd, m_colBgNorm); EnsureFonts(); SetRowHeight(m_rowHeight); } void CCarrierSlotSelector::OnShowWindow(BOOL bShow, UINT nStatus) { CListCtrl::OnShowWindow(bShow, nStatus); if (bShow && !m_bFirstShown) { m_bFirstShown = TRUE; RedrawWindow(nullptr, nullptr, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN | RDW_UPDATENOW); } } void CCarrierSlotSelector::OnWindowPosChanged(WINDOWPOS* wp) { CListCtrl::OnWindowPosChanged(wp); if (wp && (wp->flags & SWP_SHOWWINDOW)) { RedrawWindow(nullptr, nullptr, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN | RDW_UPDATENOW); } } void CCarrierSlotSelector::EnsureFonts() { if (!(HFONT)m_fntText) { LOGFONT lf = { 0 }; CFont* pSys = GetFont(); if (pSys) pSys->GetLogFont(&lf); else { lf.lfHeight = -14; lstrcpy(lf.lfFaceName, _T("Segoe UI")); } m_fntText.CreateFontIndirect(&lf); lf.lfWeight = FW_SEMIBOLD; m_fntBold.CreateFontIndirect(&lf); lf.lfWeight = FW_NORMAL; lf.lfHeight = -12; m_fntSmall.CreateFontIndirect(&lf); } } void CCarrierSlotSelector::InitGrid(int nPorts, int nSlots) { ASSERT(nPorts >= 1 && nSlots >= 1); m_ports.clear(); m_ports.resize(nPorts); m_nSlots = nSlots; for (auto& pc : m_ports) pc.slots.resize(m_nSlots); SetRedraw(FALSE); DeleteAllItems(); while (GetHeaderCtrl() && GetHeaderCtrl()->GetItemCount() > 0) DeleteColumn(0); InsertColumn(0, _T("Slot"), LVCFMT_LEFT, m_slotColWidth); for (int c = 0; c < nPorts; ++c) { CString col; col.Format(_T("Port %d"), c + 1); InsertColumn(c + 1, col, LVCFMT_LEFT, m_portColWidth); m_ports[c].portName = col; m_ports[c].carrierName.Empty(); } UpdateRowCount(); RebuildTexts(); SetRedraw(TRUE); if (IsWindowVisible()) Invalidate(FALSE); } void CCarrierSlotSelector::SetColumnWidths(int slotColWidth, int portColWidth) { if (slotColWidth > 0) m_slotColWidth = slotColWidth; if (portColWidth > 0) m_portColWidth = portColWidth; SetColumnWidth(0, m_slotColWidth); for (int c = 0; c < (int)m_ports.size(); ++c) SetColumnWidth(c + 1, m_portColWidth); if (IsWindowVisible()) Invalidate(FALSE); } void CCarrierSlotSelector::SetRowHeight(int cy) { cy = max(18, min(cy, 64)); m_rowHeight = cy; if ((HIMAGELIST)m_ilRowHeight) m_ilRowHeight.DeleteImageList(); m_ilRowHeight.Create(1, m_rowHeight, ILC_COLOR32, 1, 1); // 1¡Ácy ͸Ã÷λͼ CBitmap bmp; bmp.CreateBitmap(1, m_rowHeight, 1, 32, nullptr); m_ilRowHeight.Add(&bmp, RGB(0, 0, 0)); SetImageList(&m_ilRowHeight, LVSIL_SMALL); if (IsWindowVisible()) Invalidate(FALSE); } void CCarrierSlotSelector::UpdateRowCount() { int cur = GetItemCount(); if (cur < m_nSlots) { for (int i = cur; i < m_nSlots; ++i) { CString s; s.Format(_T("Slot %d"), i + 1); InsertItem(i, s, 0); // Éè iImage=0£¬ÐиßÀ´×Ô small image list } } else if (cur > m_nSlots) { for (int i = cur - 1; i >= m_nSlots; --i) DeleteItem(i); } // ÒÑÓÐÐÐҲͳһÉè iImage=0 LVITEM lvi = { 0 }; lvi.mask = LVIF_IMAGE; lvi.iImage = 0; for (int i = 0; i < m_nSlots; ++i) { lvi.iItem = i; SetItem(&lvi); } } void CCarrierSlotSelector::RebuildTexts() { // ÁÐÍ·£ºÏÔʾ ¡°ÒÑÑ¡Êý/×ܲÛÊý £« [x]/[ ]¡± for (int c = 0; c < (int)m_ports.size(); ++c) { int selected = 0; int total = m_nSlots; bool anyCheckable = false; bool allChecked = true; for (int r = 0; r < m_nSlots; ++r) { const auto& cell = m_ports[c].slots[r]; if (cell.hasGlass) { anyCheckable = true; if (cell.checked) ++selected; else allChecked = false; } } if (!anyCheckable) allChecked = false; CString head; CString chk = allChecked ? _T("[x]") : _T("[ ]"); if (!m_ports[c].carrierName.IsEmpty()) head.Format(_T("%s (%s) %d/%d %s%s"), m_ports[c].portName.GetString(), m_ports[c].carrierName.GetString(), selected, total, m_ports[c].allocated ? _T("[LOCK] ") : _T(""), chk.GetString()); else head.Format(_T("%s %d/%d %s%s"), m_ports[c].portName.GetString(), selected, total, m_ports[c].allocated ? _T("[LOCK] ") : _T(""), chk.GetString()); LVCOLUMN lvc = { 0 }; lvc.mask = LVCF_TEXT; lvc.pszText = head.GetBuffer(); SetColumn(c + 1, &lvc); head.ReleaseBuffer(); } // ÐÐÍ·Îı¾ for (int r = 0; r < m_nSlots; ++r) { CString s; s.Format(_T("Slot %d"), r + 1); SetItemText(r, 0, s); } // µ¥Ôª¸ñÁÙʱÎı¾ for (int r = 0; r < m_nSlots; ++r) for (int c = 0; c < (int)m_ports.size(); ++c) SetItemText(r, c + 1, GetDisplayId(c, r)); } void CCarrierSlotSelector::SetShowMaterialToggle(BOOL bShow) { m_bShowMatToggle = bShow; if (IsWindowVisible()) Invalidate(FALSE); } void CCarrierSlotSelector::SetPortInfo(int portIndex, LPCTSTR portName, LPCTSTR carrierName) { if (!SAFE_PORT(portIndex)) return; if (portName) m_ports[portIndex].portName = portName; if (carrierName) m_ports[portIndex].carrierName = carrierName; RebuildTexts(); if (IsWindowVisible()) Invalidate(FALSE); } void CCarrierSlotSelector::SetPortAllocated(int portIndex, BOOL allocated, LPCTSTR byName) { if (!SAFE_PORT(portIndex)) return; m_ports[portIndex].allocated = !!allocated; if (byName) m_ports[portIndex].allocatedBy = byName; else m_ports[portIndex].allocatedBy.Empty(); if (allocated) for (int r = 0; r < m_nSlots; ++r) m_ports[portIndex].slots[r].checked = false; // Ë¢ÐÂÕûÁÐ for (int r = 0; r < m_nSlots; ++r) { CRect rc; GetSubItemRect(r, portIndex + 1, LVIR_BOUNDS, rc); InvalidateRect(&rc, FALSE); } RebuildTexts(); } BOOL CCarrierSlotSelector::IsPortAllocated(int portIndex) const { if (!SAFE_PORT(portIndex)) return FALSE; return m_ports[portIndex].allocated; } void CCarrierSlotSelector::SetSlotGlass(int portIndex, int slotIndex, BOOL hasGlass, LPCTSTR coreId, int material) { if (!SAFE_PORT(portIndex) || !SAFE_SLOT(slotIndex)) return; auto& cell = m_ports[portIndex].slots[slotIndex]; cell.hasGlass = !!hasGlass; cell.coreId = coreId ? coreId : _T(""); cell.material = (material == MAT_G2) ? MAT_G2 : MAT_G1; if (!cell.hasGlass) cell.checked = false; CRect rc; GetSubItemRect(slotIndex, portIndex + 1, LVIR_BOUNDS, rc); InvalidateRect(&rc, FALSE); RebuildTexts(); } void CCarrierSlotSelector::SetSlotChecked(int portIndex, int slotIndex, BOOL checked) { if (!SAFE_PORT(portIndex) || !SAFE_SLOT(slotIndex)) return; if (m_ports[portIndex].allocated) return; auto& cell = m_ports[portIndex].slots[slotIndex]; if (!cell.hasGlass) return; cell.checked = !!checked; NotifySelectionChanged(portIndex, slotIndex, cell.checked); CRect rc; GetSubItemRect(slotIndex, portIndex + 1, LVIR_BOUNDS, rc); InvalidateRect(&rc, FALSE); RebuildTexts(); } BOOL CCarrierSlotSelector::GetSlotChecked(int portIndex, int slotIndex) const { if (!SAFE_PORT(portIndex) || !SAFE_SLOT(slotIndex)) return FALSE; return m_ports[portIndex].slots[slotIndex].checked ? TRUE : FALSE; } int CCarrierSlotSelector::GetSlotMaterialType(int portIndex, int slotIndex) const { if (!SAFE_PORT(portIndex) || !SAFE_SLOT(slotIndex)) return MAT_G1; return m_ports[portIndex].slots[slotIndex].material; } void CCarrierSlotSelector::SetSlotMaterialType(int portIndex, int slotIndex, int material, BOOL bNotify) { if (!SAFE_PORT(portIndex) || !SAFE_SLOT(slotIndex)) return; if (m_ports[portIndex].allocated) return; auto& cell = m_ports[portIndex].slots[slotIndex]; if (!cell.hasGlass) return; int mt = (material == MAT_G2) ? MAT_G2 : MAT_G1; if (cell.material != mt) { cell.material = mt; if (bNotify) NotifyMaterialChanged(portIndex, slotIndex, cell.material); CRect rc; GetSubItemRect(slotIndex, portIndex + 1, LVIR_BOUNDS, rc); InvalidateRect(&rc, FALSE); } } CString CCarrierSlotSelector::GetDisplayId(int portIndex, int slotIndex) const { CString s(_T("¡ª")); if (!SAFE_PORT(portIndex) || !SAFE_SLOT(slotIndex)) return s; const auto& cell = m_ports[portIndex].slots[slotIndex]; if (!cell.hasGlass) return s; s.Format(_T("G%d-%s"), (cell.material == MAT_G2) ? 2 : 1, cell.coreId.GetString()); return s; } void CCarrierSlotSelector::CheckAllInPort(int portIndex, BOOL checked, BOOL bNotify) { if (!SAFE_PORT(portIndex)) return; if (m_ports[portIndex].allocated) return; for (int r = 0; r < m_nSlots; ++r) { auto& cell = m_ports[portIndex].slots[r]; if (!cell.hasGlass) continue; if (cell.checked != !!checked) { cell.checked = !!checked; if (bNotify) NotifySelectionChanged(portIndex, r, cell.checked); } CRect rc; GetSubItemRect(r, portIndex + 1, LVIR_BOUNDS, rc); InvalidateRect(&rc, FALSE); } RebuildTexts(); } BOOL CCarrierSlotSelector::OnEraseBkgnd(CDC* /*pDC*/) { // ¹Ø¼ü£º²»ÈÃϵͳ²Á°×±³¾°£»ÓÃ×Ô»æÔÚ PREPAINT ½×¶ÎͳһÆÌµ× return TRUE; } void CCarrierSlotSelector::OnPaint() { CPaintDC dc(this); CRect rc; GetClientRect(&rc); CDC memDC; memDC.CreateCompatibleDC(&dc); CBitmap bmp; bmp.CreateCompatibleBitmap(&dc, rc.Width(), rc.Height()); HGDIOBJ hOldBmp = memDC.SelectObject(bmp); // ͳһµ×É«£¨±ÜÃâÈκβÁ°×£© memDC.FillSolidRect(rc, m_colBgNorm); // Èÿؼþ°Ñ¿Í»§ÇøÄÚÈÝ¡°»­µ½¡±ÄÚ´æDC£¨»á´¥·¢ NM_CUSTOMDRAW£¬×ßÄãÏÖÓÐ×Ô»æÂß¼­£© // PRF_ERASEBKGND ÈÃÄÚ²¿Èç¹ûÏë²Á±³¾°£¬Ò²ÔÚÄÚ´æÀï²Á£¬²»»áÉÁÆÁ SendMessage(WM_PRINTCLIENT, reinterpret_cast(memDC.m_hDC), PRF_CLIENT | PRF_ERASEBKGND | PRF_CHILDREN | PRF_OWNED); // »ØÏÔµ½ÆÁÄ» dc.BitBlt(0, 0, rc.Width(), rc.Height(), &memDC, 0, 0, SRCCOPY); memDC.SelectObject(hOldBmp); // bmp, memDC Îö¹¹×Ô¶¯ÊÍ·Å } void CCarrierSlotSelector::OnSize(UINT nType, int cx, int cy) { CListCtrl::OnSize(nType, cx, cy); } CRect CCarrierSlotSelector::GetCheckboxRect(const CRect& cell) const { int sz = max(14, min(int(m_rowHeight * 0.70), 20)); int leftPad = 8; int top = cell.top + (m_rowHeight - sz) / 2; return CRect(cell.left + leftPad, top, cell.left + leftPad + sz, top + sz); } CRect CCarrierSlotSelector::GetMaterialTagRect(const CRect& cell) const { int tagH = max(14, min(int(m_rowHeight * 0.65), m_rowHeight - 8)); int tagW = 32; int rightPadForDot = 16; int gap = 6; int top = cell.top + (m_rowHeight - tagH) / 2; int right = cell.right - rightPadForDot - gap; return CRect(right - tagW, top, right, top + tagH); } CRect CCarrierSlotSelector::GetStatusDotRect(const CRect& cell) const { int d = max(8, min(int(m_rowHeight * 0.42), 12)); int rightPad = 6; int top = cell.top + (m_rowHeight - d) / 2; return CRect(cell.right - rightPad - d, top, cell.right - rightPad, top + d); } void CCarrierSlotSelector::DrawFlatCheckbox(CDC* pDC, const CRect& r, bool checked, bool disabled) { CBrush br(disabled ? RGB(245, 245, 245) : RGB(255, 255, 255)); CPen pen(PS_SOLID, 1, disabled ? RGB(200, 200, 200) : RGB(130, 130, 135)); CBrush* pOldB = pDC->SelectObject(&br); CPen* pOldP = pDC->SelectObject(&pen); pDC->RoundRect(r, CPoint(3, 3)); pDC->SelectObject(pOldB); pDC->SelectObject(pOldP); br.DeleteObject(); pen.DeleteObject(); if (!checked) return; COLORREF c = disabled ? RGB(160, 160, 160) : RGB(40, 150, 90); CPen penTick(PS_SOLID, max(2, r.Height() / 8), c); CPen* pOld = pDC->SelectObject(&penTick); POINT p1 = { r.left + r.Width() * 2 / 9, r.top + r.Height() * 5 / 9 }; POINT p2 = { r.left + r.Width() * 4 / 9, r.top + r.Height() * 7 / 9 }; POINT p3 = { r.left + r.Width() * 7 / 9, r.top + r.Height() * 3 / 9 }; pDC->MoveTo(p1); pDC->LineTo(p2); pDC->LineTo(p3); pDC->SelectObject(pOld); penTick.DeleteObject(); } void CCarrierSlotSelector::OnLButtonDown(UINT nFlags, CPoint point) { LVHITTESTINFO ht = { 0 }; ht.pt = point; int row = SubItemHitTest(&ht); int sub = (row >= 0) ? ht.iSubItem : -1; if (row >= 0 && sub >= 1) { int port = sub - 1; if (SAFE_PORT(port) && SAFE_SLOT(row)) { auto& pc = m_ports[port]; auto& cell = pc.slots[row]; CRect rcCell; GetSubItemRect(row, sub, LVIR_BOUNDS, rcCell); if (pc.allocated || !cell.hasGlass) { CListCtrl::OnLButtonDown(nFlags, point); return; } if (GetCheckboxRect(rcCell).PtInRect(point)) { cell.checked = !cell.checked; NotifySelectionChanged(port, row, cell.checked); InvalidateRect(&rcCell, FALSE); RebuildTexts(); return; } if (m_bShowMatToggle && GetMaterialTagRect(rcCell).PtInRect(point)) { cell.material = (cell.material == MAT_G1) ? MAT_G2 : MAT_G1; NotifyMaterialChanged(port, row, cell.material); InvalidateRect(&rcCell, FALSE); return; } } } CListCtrl::OnLButtonDown(nFlags, point); } void CCarrierSlotSelector::OnMouseMove(UINT nFlags, CPoint point) { CListCtrl::OnMouseMove(nFlags, point); } void CCarrierSlotSelector::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult) { NMLVCUSTOMDRAW* pCD = reinterpret_cast(pNMHDR); switch (pCD->nmcd.dwDrawStage) { case CDDS_PREPAINT: { // ¹Ø¼ü£ºÕû¿Ø¼þÔ¤ÏÈÆÌµ×£¬±ÜÃâ³õ´Î hover/ÏÔʾʱ¡°Ë¢°×¡± CDC* pDC = CDC::FromHandle(pCD->nmcd.hdc); CRect rcClient; GetClientRect(&rcClient); pDC->FillSolidRect(rcClient, m_colBgNorm); *pResult = CDRF_NOTIFYITEMDRAW; return; } case CDDS_ITEMPREPAINT: *pResult = CDRF_NOTIFYSUBITEMDRAW; return; case (CDDS_SUBITEM | CDDS_ITEMPREPAINT): { CDC* pDC = CDC::FromHandle(pCD->nmcd.hdc); int row = (int)pCD->nmcd.dwItemSpec; int sub = pCD->iSubItem; CRect rc; GetSubItemRect(row, sub, LVIR_BOUNDS, rc); // ±³¾° COLORREF bk = m_colBgNorm; if (sub >= 1) { int port = sub - 1; if (port % 2 == 0) bk = m_colBgAlt; // ½»ÌæÁÐ if (SAFE_PORT(port) && m_ports[port].allocated) // Ëø¶¨ÁÐ bk = m_colLockBg; } pDC->FillSolidRect(rc, bk); // Íø¸ñ£¨ÉÏ/×ó¼Ó´Ö£»ÓÒ/ÏÂϸÏߣ© CPen penTopLeft(PS_SOLID, (sub >= 1 && ((sub - 1) % 2 == 0)) ? 2 : 1, RGB(210, 214, 220)); CPen* pOldPen = pDC->SelectObject(&penTopLeft); pDC->MoveTo(rc.left, rc.top); pDC->LineTo(rc.right, rc.top); pDC->MoveTo(rc.left, rc.top); pDC->LineTo(rc.left, rc.bottom); pDC->SelectObject(pOldPen); penTopLeft.DeleteObject(); CPen penThin(PS_SOLID, 1, RGB(220, 224, 230)); pOldPen = pDC->SelectObject(&penThin); if (sub == GetHeaderCtrl()->GetItemCount() - 1) { pDC->MoveTo(rc.right - 1, rc.top); pDC->LineTo(rc.right - 1, rc.bottom); } if (row == m_nSlots - 1) { pDC->MoveTo(rc.left, rc.bottom - 1); pDC->LineTo(rc.right, rc.bottom - 1); } pDC->SelectObject(pOldPen); penThin.DeleteObject(); if (sub == 0) { CString s; s.Format(_T("Slot %d"), row + 1); CFont* pOld = pDC->SelectObject(&m_fntBold); pDC->SetBkMode(TRANSPARENT); pDC->SetTextColor(RGB(60, 60, 64)); CRect rText = rc; rText.DeflateRect(8, 0, 8, 0); pDC->DrawText(s, rText, DT_LEFT | DT_VCENTER | DT_SINGLELINE); pDC->SelectObject(pOld); } else if (SAFE_PORT(sub - 1) && SAFE_SLOT(row)) { int port = sub - 1; const auto& pc = m_ports[port]; const auto& cell = pc.slots[row]; // ±âƽ¸´Ñ¡¿ò CRect rChk = GetCheckboxRect(rc); DrawFlatCheckbox(pDC, rChk, cell.checked, pc.allocated || !cell.hasGlass); // Îı¾ CString s = GetDisplayId(port, row); CRect rText = rc; int leftPad = rChk.right + 6; CRect rDot = GetStatusDotRect(rc); CRect rTag = GetMaterialTagRect(rc); int rightPad = rc.right - min(rTag.left - 6, rDot.left - 6); rText.DeflateRect(leftPad - rc.left, 0, rightPad, 0); CFont* pOld = pDC->SelectObject(&m_fntText); pDC->SetBkMode(TRANSPARENT); pDC->SetTextColor(cell.hasGlass ? RGB(40, 40, 40) : RGB(150, 150, 150)); pDC->DrawText(s, rText, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS); pDC->SelectObject(pOld); // ÎïÁϱêÇ©£¨¿ÉÒþ²Ø£© if (m_bShowMatToggle) { CRect rT = rTag; COLORREF crBorder = (cell.material == MAT_G2) ? RGB(180, 150, 220) : RGB(120, 160, 220); COLORREF crFill = (cell.material == MAT_G2) ? RGB(243, 235, 250) : RGB(233, 240, 252); COLORREF crText = (cell.material == MAT_G2) ? RGB(90, 60, 150) : RGB(50, 90, 160); if (pc.allocated || !cell.hasGlass) { crBorder = RGB(210, 210, 210); crFill = RGB(245, 245, 245); crText = RGB(160, 160, 160); } CBrush br(crFill); CPen tagPen(PS_SOLID, 1, crBorder); CPen* pOldP = pDC->SelectObject(&tagPen); CBrush* pOldB = pDC->SelectObject(&br); pDC->RoundRect(rT, CPoint(6, 6)); pDC->SelectObject(pOldB); pDC->SelectObject(pOldP); br.DeleteObject(); tagPen.DeleteObject(); CString t; t.Format(_T("G%d"), (cell.material == MAT_G2) ? 2 : 1); CFont* pOldS = pDC->SelectObject(&m_fntSmall); pDC->SetBkMode(TRANSPARENT); pDC->SetTextColor(crText); pDC->DrawText(t, rT, DT_CENTER | DT_VCENTER | DT_SINGLELINE); pDC->SelectObject(pOldS); } // ״̬µã CRect rD = GetStatusDotRect(rc); COLORREF dot = cell.hasGlass ? (pc.allocated ? RGB(215, 160, 60) : RGB(60, 170, 80)) : RGB(160, 160, 160); CBrush bDot(dot); CBrush* pOldB = pDC->SelectObject(&bDot); pDC->Ellipse(rD); pDC->SelectObject(pOldB); bDot.DeleteObject(); } *pResult = CDRF_SKIPDEFAULT; // ×ÓÏîÍêÈ«×Ô»æ return; } default: break; } *pResult = 0; } BOOL CCarrierSlotSelector::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) { NMHDR* pNM = reinterpret_cast(lParam); if (pNM && pNM->hwndFrom == GetHeaderCtrl()->GetSafeHwnd()) { switch (pNM->code) { case HDN_ITEMCLICKA: case HDN_ITEMCLICKW: { HD_NOTIFY* phdn = reinterpret_cast(lParam); OnHeaderClick(phdn->iItem); if (pResult) *pResult = 0; return TRUE; // ÎÒÃÇÒÑ´¦Àí } default: break; } } return CListCtrl::OnNotify(wParam, lParam, pResult); } void CCarrierSlotSelector::OnHeaderClick(int iItem) { // iItem: 0=Slot ÁУ¬>=1 Ϊ Port ÁÐ if (iItem <= 0) return; int port = iItem - 1; if (!SAFE_PORT(port) || m_ports[port].allocated) return; // ¼ÆËãÊÇ·ñ¡°È«Ñ¡¡± bool anyCheckable = false; bool allChecked = true; for (int r = 0; r < m_nSlots; ++r) { const auto& cell = m_ports[port].slots[r]; if (!cell.hasGlass) continue; anyCheckable = true; if (!cell.checked) { allChecked = false; break; } } if (!anyCheckable) return; // Çл»£ºÈôÒÑȫѡ -> È¡Ïûȫѡ£»·ñÔò -> ȫѡ CheckAllInPort(port, allChecked ? FALSE : TRUE, TRUE); } // ==== ֪ͨ ==== void CCarrierSlotSelector::NotifySelectionChanged(int /*port*/, int /*slot*/, BOOL /*checked*/) { if (GetParent()) { const int code = 0x2001; // CSSN_SELECTION_CHANGED GetParent()->SendMessage(WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), code), (LPARAM)m_hWnd); } } void CCarrierSlotSelector::NotifyMaterialChanged(int /*port*/, int /*slot*/, int /*material*/) { if (GetParent()) { const int code = 0x2002; // CSSN_MATERIAL_CHANGED GetParent()->SendMessage(WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), code), (LPARAM)m_hWnd); } }