Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "stdafx.h"
- #include "OwnListCtrl.h"
- #include "ListCtrlEx.h"
- #define VK_A 0x41
- IMPLEMENT_DYNAMIC(CListCtrlEx, CListCtrl)
- CListCtrlEx::CListCtrlEx() :
- m_nFocusCell(-1)
- , m_nItem(0)
- , m_bFocus(TRUE)
- {
- m_pFont = make_shared<CFont>();
- }
- CListCtrlEx::~CListCtrlEx()
- {
- }
- BEGIN_MESSAGE_MAP(CListCtrlEx, CListCtrl)
- ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CListCtrlEx::OnCustomdraw)
- ON_WM_LBUTTONDOWN()
- ON_MESSAGE(WM_FOCUS_CHANGED, &CListCtrlEx::OnFocusChanged)
- ON_MESSAGE(WM_SETFONT, &CListCtrlEx::OnSetFont)
- ON_WM_MEASUREITEM_REFLECT()
- END_MESSAGE_MAP()
- void CListCtrlEx::GetCurrentFont(LOGFONT& lf) const
- {
- GetFont()->GetLogFont(&lf);
- }
- void CListCtrlEx::SetupFont(int nSize, const CString& strName)
- {
- if (m_pFont.get())
- m_pFont.get()->DeleteObject();
- VERIFY(m_pFont.get()->CreatePointFont(nSize, strName));
- SetFont(m_pFont.get());
- }
- LRESULT CListCtrlEx::OnSetFont(WPARAM wParam, LPARAM)
- {
- LRESULT res = Default();
- CRect rc;
- GetWindowRect(&rc);
- WINDOWPOS wp;
- ZeroMemory(&wp, sizeof(wp));
- wp.hwnd = m_hWnd;
- wp.cx = rc.Width();
- wp.cy = rc.Height();
- wp.flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER;
- SendMessage(WM_WINDOWPOSCHANGED, 0, (LPARAM)&wp);
- return res;
- }
- void CListCtrlEx::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
- {
- HDC hDC = ::GetDC(NULL);
- HFONT hFontOld = (HFONT)SelectObject(hDC, m_pFont.get()->GetSafeHandle());
- CSize size;
- GetTextExtentPoint32(hDC, _T(""), 1, &size);
- lpMeasureItemStruct->itemHeight = size.cy;
- SelectObject(hDC, hFontOld);
- ::ReleaseDC(NULL, hDC);
- }
- void CListCtrlEx::OnCustomdraw(NMHDR *pNMHDR, LRESULT *pResult)
- {
- NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>(pNMHDR);
- int nRow = (int)pLVCD->nmcd.dwItemSpec;
- switch (pLVCD->nmcd.dwDrawStage)
- {
- case CDDS_PREPAINT:
- *pResult |= CDRF_NOTIFYITEMDRAW;
- break;
- // до отрисовки элемента
- case CDDS_ITEMPREPAINT:
- {
- if (pLVCD->nmcd.uItemState & CDIS_FOCUS)
- {
- if (GetNextItem(-1, LVNI_FOCUSED) == nRow)
- {
- // мы хотим нарисовать фокус для ячейки вместо фокуса всего элемента
- pLVCD->nmcd.uItemState &= ~CDIS_FOCUS;
- *pResult |= CDRF_NOTIFYPOSTPAINT;
- }
- }
- ::SelectObject(pLVCD->nmcd.hdc, (HFONT)m_pFont.get());
- *pResult |= CDRF_NEWFONT;
- }
- break;
- // после отрисовки полного элемента
- case CDDS_ITEMPOSTPAINT:
- {
- if (GetNextItem(-1, LVNI_FOCUSED) != nRow)
- break;
- // рисуем фокусный прямоугольник для одной ячейки
- CRect rcFocus;
- CDC* pDC = CDC::FromHandle(pLVCD->nmcd.hdc);
- VERIFY(GetCellRect(nRow, m_nFocusCell, rcFocus));
- // выравниваем прямоугольник в соответствии с линиями сетки
- if (GetExtendedStyle() & LVS_EX_GRIDLINES)
- {
- int cxborder = ::GetSystemMetrics(SM_CXBORDER);
- // колонки после первой видимой колонки должны учитывать границу сетки слева
- if (GetHeaderCtrl()->OrderToIndex(m_nFocusCell) != 0)
- rcFocus.left += cxborder;
- rcFocus.bottom -= cxborder;
- }
- pDC->DrawFocusRect(rcFocus);
- }
- break;
- }
- }
- BOOL CListCtrlEx::GetCellRect(int nRow, int nCol, CRect& rect)
- {
- // Find the top and bottom of the cell-rectangle
- CRect rowRect;
- if (GetItemRect(nRow, rowRect, LVIR_BOUNDS) == FALSE)
- return FALSE;
- // Find the left and right of the cell-rectangle using the CHeaderCtrl
- CRect colRect;
- if (GetHeaderCtrl()->GetItemRect(nCol, colRect) == FALSE)
- return FALSE;
- // Adjust for scrolling
- colRect.left -= GetScrollPos(SB_HORZ);
- colRect.right -= GetScrollPos(SB_HORZ);
- rect.left = colRect.left;
- rect.top = rowRect.top;
- rect.right = colRect.right;
- rect.bottom = rowRect.bottom;
- return TRUE;
- }
- void CListCtrlEx::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
- {
- CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
- int nItem = lpDrawItemStruct->itemID;
- // Save dc state
- int nSavedDC = pDC->SaveDC();
- // Get rectangles for drawing
- CRect rcBounds, rcLabel;
- VERIFY(GetItemRect(nItem, rcBounds, LVIR_BOUNDS));
- VERIFY(GetItemRect(nItem, rcLabel, LVIR_LABEL));
- // Should the item be highlighted
- BOOL bHighlight = (GetItemState(nItem, LVIS_SELECTED) == LVIS_SELECTED);
- if (bHighlight)
- {
- pDC->SetBkColor(::GetSysColor(m_bFocus ? COLOR_HIGHLIGHT : COLOR_INACTIVECAPTION));
- if (nItem != m_nItem)
- {
- pDC->FillRect(rcBounds, &CBrush(::GetSysColor(m_bFocus ? COLOR_HIGHLIGHT : COLOR_INACTIVECAPTION)));
- }
- else if (m_nFocusCell == 0) // selected the first cell
- {
- CRect rcRightCell;
- GetCellRect(nItem, m_nFocusCell + 1, rcRightCell);
- HighLightItem(TRUE, rcBounds, rcRightCell, pDC);
- }
- else if (m_nFocusCell + 1 == GetHeaderCtrl()->GetItemCount()) // selected the last cell
- {
- CRect rcLeftCell;
- GetCellRect(nItem, m_nFocusCell - 1, rcLeftCell);
- HighLightItem(FALSE, rcBounds, rcLeftCell, pDC);
- }
- else // selected somewhere else cell
- {
- CRect rcLeftCell;
- GetCellRect(nItem, m_nFocusCell - 1, rcLeftCell);
- HighLightItem(FALSE, rcBounds, rcLeftCell, pDC);
- CRect rcRightCell;
- GetCellRect(nItem, m_nFocusCell + 1, rcRightCell);
- HighLightItem(TRUE, rcBounds, rcRightCell, pDC);
- }
- }
- // Perform the drawing of the focus rectangle
- // for the first cell in list control
- if (m_nFocusCell == -1)
- DrawInitialCell(rcBounds, pDC);
- CRect rcCol(rcBounds);
- // Set clip region
- rcCol.right = rcCol.left + GetColumnWidth(0);
- // Labels are offset by a certain amount
- // This offset is related to the width of a space character
- int offset = pDC->GetTextExtent(_T(" "), 1).cx * 2;
- // Draw item label - Column 0
- rcLabel.left += offset / 2;
- rcLabel.right -= offset;
- CString sLabel = GetItemText(nItem, 0);
- if (bHighlight && m_nFocusCell != 0 || bHighlight && nItem != m_nItem)
- pDC->SetTextColor(::GetSysColor(m_bFocus ? COLOR_HIGHLIGHTTEXT : COLOR_INACTIVECAPTIONTEXT));
- else
- {
- pDC->SetTextColor(::GetSysColor(COLOR_WINDOWTEXT));
- pDC->SetBkColor(::GetSysColor(COLOR_WINDOW));
- }
- pDC->DrawText(sLabel, rcLabel, DT_LEFT | DT_SINGLELINE |
- DT_NOPREFIX | DT_NOCLIP | DT_END_ELLIPSIS | DT_VCENTER);
- // Draw labels for remaining columns
- LV_COLUMN lvc;
- lvc.mask = LVCF_FMT | LVCF_WIDTH;
- for (int nColumn = 1; GetColumn(nColumn, &lvc); nColumn++)
- {
- rcCol.left = rcCol.right;
- rcCol.right += lvc.cx;
- sLabel = GetItemText(nItem, nColumn);
- if (sLabel.IsEmpty())
- continue;
- rcLabel = rcCol;
- rcLabel.left += offset;
- rcLabel.right -= offset;
- if (bHighlight && m_nFocusCell != nColumn || bHighlight && nItem != m_nItem)
- pDC->SetTextColor(::GetSysColor(m_bFocus ? COLOR_HIGHLIGHTTEXT : COLOR_INACTIVECAPTIONTEXT));
- else
- pDC->SetTextColor(::GetSysColor(COLOR_WINDOWTEXT));
- pDC->DrawText(sLabel, rcLabel, DT_LEFT | DT_SINGLELINE |
- DT_NOPREFIX | DT_END_ELLIPSIS | DT_VCENTER);
- }
- // Restore dc
- pDC->RestoreDC(nSavedDC);
- }
- void CListCtrlEx::HighLightItem(BOOL bRight, const CRect& rcBounds, const CRect& rcCell, CDC* const pDC)
- {
- CRect rcHighLight;
- rcHighLight.top = rcBounds.top;
- rcHighLight.bottom = rcBounds.bottom;
- rcHighLight.right = (bRight) ? rcBounds.right : rcCell.right;
- rcHighLight.left = (bRight) ? rcCell.left : rcBounds.left;
- pDC->FillRect(rcHighLight, &CBrush(::GetSysColor(m_bFocus ? COLOR_HIGHLIGHT : COLOR_INACTIVECAPTION)));
- }
- void CListCtrlEx::DrawInitialCell(const CRect& rcBounds, CDC* const pDC)
- {
- CRect rect;
- rect = rcBounds;
- // Draw the focus-rectangle for a single-cell
- VERIFY(GetCellRect(0, 0, rect));
- // Adjust rectangle according to grid-lines
- if (GetExtendedStyle() & LVS_EX_GRIDLINES)
- rect.bottom -= ::GetSystemMetrics(SM_CXBORDER);
- m_nFocusCell = 0;
- m_nItem = 0;
- pDC->DrawFocusRect(rect);
- SetItemState(0, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED);
- }
- BOOL CListCtrlEx::PreTranslateMessage(MSG* pMsg)
- {
- if (pMsg->message == WM_KEYDOWN)
- {
- switch (pMsg->wParam)
- {
- case VK_A:
- {
- if (::GetKeyState(VK_CONTROL) < 0)
- {
- if (!(GetStyle() & LVS_SINGLESEL))
- SetItemState(-1, -1, LVIS_SELECTED);
- }
- break;
- }
- case VK_LEFT:
- {
- if (::GetKeyState(VK_CONTROL) < 0)
- return TRUE;
- if (::GetKeyState(VK_SHIFT) >= 0 &&
- !(GetStyle() & LVS_SINGLESEL))
- {
- SetItemState(-1, 0, LVIS_SELECTED);
- SetItemState(m_nItem, LVIS_SELECTED, LVIS_SELECTED);
- }
- MoveFocusCell(false);
- }
- break;
- case VK_RIGHT:
- {
- if (::GetKeyState(VK_CONTROL) < 0)
- return TRUE;
- if (::GetKeyState(VK_SHIFT) >= 0 &&
- !(GetStyle() & LVS_SINGLESEL))
- {
- SetItemState(-1, 0, LVIS_SELECTED);
- SetItemState(m_nItem, LVIS_SELECTED, LVIS_SELECTED);
- }
- MoveFocusCell(true);
- }
- break;
- case VK_UP:
- {
- if (::GetKeyState(VK_CONTROL) < 0)
- return TRUE;
- if (m_nItem > 0)
- m_nItem--;
- }
- break;
- case VK_DOWN:
- {
- if (::GetKeyState(VK_CONTROL) < 0)
- return TRUE;
- if (m_nItem + 1 < GetItemCount())
- m_nItem++;
- }
- break;
- case VK_ESCAPE:
- {
- if (!(GetStyle() & LVS_SINGLESEL))
- {
- if (GetSelectedCount() > 1)
- VERIFY(SetItemState(-1, 0, LVIS_SELECTED));
- }
- }
- case VK_RETURN:
- return TRUE;
- default:
- break;
- }
- }
- return CListCtrl::PreTranslateMessage(pMsg);
- }
- void CListCtrlEx::OnLButtonDown(UINT nFlags, CPoint point)
- {
- LVHITTESTINFO hitinfo = {0};
- hitinfo.flags = nFlags;
- hitinfo.pt = point;
- SubItemHitTest(&hitinfo);
- if (hitinfo.iSubItem != -1)
- {
- m_nItem = hitinfo.iItem;
- // Update the focused cell before calling CListCtrl::OnLButtonDown()
- // as it might cause a row-repaint
- m_nFocusCell = hitinfo.iSubItem;
- CListCtrl::OnLButtonDown(nFlags, point);
- // CListCtrl::OnLButtonDown() doesn't always cause a row-repaint
- // call our own method to ensure the row is repainted
- UpdateFocusCell(hitinfo.iSubItem);
- }
- }
- // Force redraw of focus row, so the focus cell becomes visible
- void CListCtrlEx::UpdateFocusCell(int nCol)
- {
- m_nFocusCell = nCol; // Update focus cell before starting re-draw
- int nFocusRow = GetNextItem(-1, LVNI_FOCUSED);
- if (nFocusRow >= 0)
- {
- CRect itemRect;
- VERIFY(GetItemRect(nFocusRow, itemRect, LVIR_BOUNDS));
- m_nItem = nFocusRow;
- InvalidateRect(itemRect);
- UpdateWindow();
- }
- }
- void CListCtrlEx::MoveFocusCell(bool right)
- {
- if (GetItemCount() <= 0)
- return;
- // Convert focus-cell to order index
- int nOrderIndex = -1;
- for (int i = 0; i < GetHeaderCtrl()->GetItemCount(); ++i)
- {
- int nCol = GetHeaderCtrl()->OrderToIndex(i);
- if (nCol == m_nFocusCell)
- {
- nOrderIndex = i;
- break;
- }
- }
- // Move to the following column
- if (right)
- nOrderIndex++;
- else
- nOrderIndex--;
- // Convert order-index to focus cell
- if (nOrderIndex >= 0 && nOrderIndex < GetHeaderCtrl()->GetItemCount())
- m_nFocusCell = GetHeaderCtrl()->OrderToIndex(nOrderIndex);
- // Ensure the column is visible
- if (m_nFocusCell >= 0)
- VERIFY(EnsureColumnVisible(m_nFocusCell, false));
- if (m_nFocusCell >= 0)
- UpdateFocusCell(m_nFocusCell);
- }
- BOOL CListCtrlEx::EnsureColumnVisible(int nCol, bool bPartialOK)
- {
- if (nCol < 0 || nCol >= GetHeaderCtrl()->GetItemCount())
- return FALSE;
- CRect rcHeader;
- if (GetHeaderCtrl()->GetItemRect(nCol, rcHeader) == FALSE)
- return FALSE;
- CRect rcClient;
- GetClientRect(&rcClient);
- int nOffset = GetScrollPos(SB_HORZ);
- if (bPartialOK)
- {
- if ((rcHeader.left - nOffset < rcClient.right) && (rcHeader.right - nOffset > 0))
- {
- return TRUE;
- }
- }
- int nScrollX = 0;
- if ((rcHeader.Width() > rcClient.Width()) || (rcHeader.left - nOffset < 0))
- {
- nScrollX = rcHeader.left - nOffset;
- }
- else if(rcHeader.right - nOffset > rcClient.right)
- {
- nScrollX = rcHeader.right - nOffset - rcClient.right;
- }
- if (nScrollX != 0)
- {
- CSize size(nScrollX, 0);
- if (Scroll(size) == FALSE)
- return FALSE;
- }
- return TRUE;
- }
- void CListCtrlEx::PreSubclassWindow()
- {
- SetExtendedStyle(GetExtendedStyle() | LVS_EX_GRIDLINES);
- SetExtendedStyle(GetExtendedStyle() | LVS_EX_DOUBLEBUFFER); // anti-flickering
- CListCtrl::PreSubclassWindow();
- }
- LRESULT CListCtrlEx::OnFocusChanged(WPARAM wParam, LPARAM lParam)
- {
- m_bFocus = static_cast<BOOL>(wParam);
- CRect rect;
- GetClientRect(rect);
- InvalidateRect(rect);
- return 1;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement