#include "header.h" #include "vlist.h" #include "cpaldc.h" #include "hhctrl.h" #include #include CVirtualListCtrl::CVirtualListCtrl(LCID lcid) { m_cItems = 0; m_iTopItem = 0; m_iSelItem = 0; m_cyItem = 0; m_cItemsPerPage = 0; m_fFocus = 0; m_hFont = 0; m_hWndParent = m_hWnd = 0; m_langid = PRIMARYLANGID(LANGIDFROMLCID(GetUserDefaultLCID())); m_lcid = lcid; m_fBiDi = g_fBiDi; m_RTL_Style = g_RTL_Style; // // Maybe this goo below can go away ? // m_cyBackBmp = 0; m_cxBackBmp = 0; m_hpalBackGround = 0; m_hbrBackGround = 0; m_hbmpBackGround = 0; m_clrForeground = (COLORREF) -1; m_clrBackground = (COLORREF) -1; } CVirtualListCtrl::~CVirtualListCtrl() { if ( IsValidWindow(m_hWnd) ) DestroyWindow(m_hWnd); WNDCLASSEX wci; if ( GetClassInfoEx(_Module.GetModuleInstance(), "hh_kwd_vlist", &wci) ) UnregisterClass("hh_kwd_vlist", _Module.GetModuleInstance()); } void CVirtualListCtrl::RedrawCurrentItem() { RECT rc; GetItemRect(m_iSelItem, &rc); InvalidateRect(m_hWnd, &rc, TRUE); } BOOL CVirtualListCtrl::SetItemCount(int cItems) { int scroll; if (cItems < 0) return FALSE; scroll = cItems - 1; if (scroll < 0) scroll = 0; m_cItems = cItems; m_iSelItem = m_iTopItem = 0; SetScrollRange(m_hWnd, SB_VERT, 0, scroll, TRUE); InvalidateRect(m_hWnd, NULL, FALSE); // for now return TRUE; } BOOL CVirtualListCtrl::SetSelection(int iSel, BOOL bNotify /* default = TRUE */) { if (iSel < 0 || iSel >= m_cItems) return FALSE; if (m_iSelItem != iSel) { RedrawCurrentItem(); m_iSelItem = iSel; RedrawCurrentItem(); EnsureVisible(iSel); if ( bNotify ) ItemSelected(iSel); } return TRUE; } int CVirtualListCtrl::GetSelection() { return m_iSelItem; } int CVirtualListCtrl::GetTopIndex() { return m_iTopItem; } BOOL CVirtualListCtrl::SetTopIndex(int iItem) { if (m_cItemsPerPage >= m_cItems || iItem < 0) iItem = 0; else if (iItem > m_cItems - m_cItemsPerPage) iItem = m_cItems - m_cItemsPerPage; if (iItem != m_iTopItem) { m_iTopItem = iItem; SetScrollPos(m_hWnd, SB_VERT, iItem, TRUE); InvalidateRect(m_hWnd, NULL, FALSE); // for now } return TRUE; } BOOL CVirtualListCtrl::EnsureVisible(int iItem) { if (iItem < m_iTopItem) SetTopIndex(iItem); else if (iItem >= m_iTopItem + m_cItemsPerPage) SetTopIndex(iItem - m_cItemsPerPage + 1); return TRUE; } BOOL CVirtualListCtrl::GetItemRect(int iItem, RECT* prc) { RECT rcClient; int y; GetClientRect(m_hWnd, &rcClient); y = (iItem - m_iTopItem)*m_cyItem; prc->left = rcClient.left; prc->top = y; prc->right = rcClient.right; prc->bottom = y+m_cyItem; return TRUE; } const int LEVEL_PAD = 12; LRESULT CVirtualListCtrl::DrawItem(HDC hDC, int iItem, RECT* prc, BOOL fSel, BOOL fFocus) { WCHAR szText[512]; COLORREF clrFore; COLORREF clrDisabled; COLORREF clrBack; int iLevel; int pad = 0; if (fSel) { clrFore = GetSysColor(COLOR_HIGHLIGHTTEXT); clrDisabled = GetSysColor(COLOR_GRAYTEXT); clrBack = GetSysColor(COLOR_HIGHLIGHT); } else { clrFore = (m_clrForeground == -1)?GetSysColor(COLOR_WINDOWTEXT):m_clrForeground; clrDisabled = GetSysColor(COLOR_GRAYTEXT); clrBack = (m_clrBackground == -1)?GetSysColor(COLOR_WINDOW):m_clrBackground; } szText[0] = 0x00; DWORD dwFlags = 0; if (iItem >= 0 && iItem < m_cItems) GetItemText(iItem,&iLevel,&dwFlags,szText,(sizeof(szText)/2)); BOOL bDisabled = (dwFlags & 0x1); if( bDisabled ) SetTextColor(hDC,clrDisabled); else SetTextColor(hDC,clrFore); SetBkColor(hDC,clrBack); if ( iLevel > 1 ) pad = ((iLevel - 1) * LEVEL_PAD); else pad = 2; #if 0 if (m_fBiDi) { /* * Using ExtTextOut with ETO_RTLREADING fails to clear the entire * line. So, we clear the background with FillRect first and then * display the text. */ SIZE size; GetTextExtentPointW(hDC, szText, wcslen(szText), &size); int pos = prc->right - 2 - size.cx - pad; if (pos < 2) pos = 2; HBRUSH hbrush = CreateSolidBrush(fSel ? GetSysColor(COLOR_HIGHLIGHT) : GetSysColor(COLOR_WINDOW)); FillRect(hDC, prc, hbrush); DeleteObject(hbrush); IntlExtTextOutW(hDC, prc->left + pos, prc->top, ETO_OPAQUE | ETO_RTLREADING, prc, szText, wcslen(szText), 0); } else #endif SIZE size; GetTextExtentPointW(hDC, szText, wcslen(szText), &size); int pos = prc->right - 2 - size.cx - pad; //if (pos < 2) // pos = 2; if (m_fBiDi) IntlExtTextOutW(hDC, pos, prc->top, ETO_OPAQUE|ETO_CLIPPED|ETO_RTLREADING, prc, szText, wcslen(szText), 0); else IntlExtTextOutW(hDC, prc->left + pad, prc->top, ETO_OPAQUE | ETO_CLIPPED, prc, szText, wcslen(szText), 0); if (fFocus && fSel) DrawFocusRect(hDC, prc); return 0; } LRESULT CVirtualListCtrl::Notify(int not, NMHDR * pNMHdr) { NMHDR nmhdr; if (!pNMHdr) pNMHdr = &nmhdr; pNMHdr->hwndFrom = m_hWnd; pNMHdr->idFrom = GetDlgCtrlID(m_hWnd); pNMHdr->code = not; return SendMessage(m_hWndParent, WM_NOTIFY, pNMHdr->idFrom, (LPARAM)pNMHdr); } LRESULT CVirtualListCtrl::ItemSelected(int i) { return Notify(VLN_SELECT); } LRESULT CVirtualListCtrl::ItemDoubleClicked(int i) { return Notify(NM_DBLCLK); } LRESULT CVirtualListCtrl::GetItemText(int iItem, int* piLevel, DWORD* pdwFlags, WCHAR* lpwsz, int cchMax) { VLC_ITEM it; *lpwsz = 0; it.iItem = iItem; it.lpwsz = lpwsz; it.cchMax = cchMax; Notify(VLN_GETITEM,(NMHDR*)&it); *piLevel = it.iLevel; *pdwFlags = it.dwFlags; return S_OK; } LRESULT CVirtualListCtrl::StaticWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { CVirtualListCtrl* pThis; PAINTSTRUCT ps; HDC hDC; RECT rc; SIZE cs; int i; pThis = (CVirtualListCtrl*)GetWindowLongPtr(hWnd,0); switch (msg) { case WM_CREATE: pThis = (CVirtualListCtrl*)((LPCREATESTRUCT)lParam)->lpCreateParams; SetWindowLongPtr(hWnd,0,(LONG_PTR)pThis); pThis->m_hWnd = hWnd; break; case WM_SETFONT: pThis->m_hFont = (HFONT)wParam; // FALL THRU to WM_SIZE case WM_SIZE: GetClientRect(hWnd, &rc); hDC = GetDC(hWnd); SaveDC(hDC); if (pThis->m_hFont) SelectObject(hDC, pThis->m_hFont); GetTextExtentPoint(hDC, "CC", 2, &cs); pThis->m_cyItem = cs.cy; if (pThis->m_cyItem) pThis->m_cItemsPerPage = ((rc.bottom - rc.top) / pThis->m_cyItem); else pThis->m_cItemsPerPage = 0; { SCROLLINFO si; si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_PAGE; si.nPage = pThis->m_cItemsPerPage; SetScrollInfo(hWnd, SB_VERT, &si, TRUE ); } RestoreDC(hDC, -1); ReleaseDC(hWnd, hDC); break; case WM_PAINT: hDC = BeginPaint(hWnd, &ps); SaveDC(hDC); if (pThis->m_hFont) SelectObject(hDC, pThis->m_hFont); for (i = 0; i <= pThis->m_cItemsPerPage; i++) { pThis->GetItemRect(pThis->m_iTopItem + i, &rc); pThis->DrawItem(hDC, pThis->m_iTopItem + i, &rc, pThis->m_iTopItem + i == pThis->m_iSelItem, pThis->m_fFocus); } RestoreDC(hDC, -1); EndPaint(hWnd, &ps); break; case WM_SETFOCUS: pThis->m_fFocus = 1; pThis->RedrawCurrentItem(); pThis->Notify(NM_SETFOCUS); break; case WM_KILLFOCUS: pThis->m_fFocus = 0; pThis->RedrawCurrentItem(); pThis->Notify(NM_KILLFOCUS); break; case WM_KEYDOWN: switch (wParam) { case VK_UP: i = pThis->m_iSelItem - 1; goto go_there; case VK_DOWN: i = pThis->m_iSelItem + 1; goto go_there; case VK_PRIOR: i = pThis->m_iSelItem - pThis->m_cItemsPerPage; goto go_there; case VK_NEXT: i = pThis->m_iSelItem + pThis->m_cItemsPerPage; go_there: if (i < 0) i = 0; else if (i >= pThis->m_cItems) i = pThis->m_cItems - 1; pThis->SetSelection(i); break; case VK_HOME: pThis->SetSelection(0); break; case VK_END: pThis->SetSelection(pThis->m_cItems - 1); break; case VK_RETURN: pThis->Notify(NM_RETURN); break; case VK_TAB: pThis->Notify(VLN_TAB); break; } break; case WM_MOUSEWHEEL: if (! SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &i, 0) ) i = 3; if( (short) HIWORD(wParam) > 0 ) pThis->SetTopIndex(pThis->m_iTopItem - i); else pThis->SetTopIndex(pThis->m_iTopItem + i); break; case WM_VSCROLL: switch (LOWORD(wParam)) { case SB_LINEUP: pThis->SetTopIndex(pThis->m_iTopItem - 1); break; case SB_LINEDOWN: pThis->SetTopIndex(pThis->m_iTopItem + 1); break; case SB_PAGEUP: pThis->SetTopIndex(pThis->m_iTopItem - pThis->m_cItemsPerPage); break; case SB_PAGEDOWN: pThis->SetTopIndex(pThis->m_iTopItem + pThis->m_cItemsPerPage); break; case SB_BOTTOM: pThis->SetTopIndex(pThis->m_cItems); break; case SB_TOP: pThis->SetTopIndex(0); break; case SB_THUMBPOSITION: case SB_THUMBTRACK: if( pThis->m_cItems > 65535 ) { SCROLLINFO si; si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_TRACKPOS; GetScrollInfo(hWnd, SB_VERT, &si); pThis->SetTopIndex( si.nTrackPos ); } else pThis->SetTopIndex( HIWORD( wParam ) ); break; } break; case WM_LBUTTONDOWN: SetFocus(hWnd); if (pThis->m_cyItem) pThis->SetSelection(pThis->m_iTopItem + (HIWORD(lParam) / pThis->m_cyItem)); pThis->Notify(NM_CLICK); break; case WM_LBUTTONDBLCLK: SetFocus(hWnd); if (pThis->m_cyItem) if (pThis->m_iSelItem == (pThis->m_iTopItem + (HIWORD(lParam) / pThis->m_cyItem))) pThis->ItemDoubleClicked(pThis->m_iSelItem); break; case WM_RBUTTONDOWN: SetFocus(hWnd); pThis->Notify(NM_RCLICK); break; case WM_RBUTTONDBLCLK: SetFocus(hWnd); pThis->Notify(NM_RDBLCLK); break; case WM_GETDLGCODE: return DLGC_WANTARROWS; break; case WM_ERASEBKGND: if ( pThis->m_hbmpBackGround ) { RECT rc; HDC hdc = (HDC) wParam; GetClientRect(hWnd, &rc); CPalDC dc(pThis->m_hbmpBackGround); HPALETTE hpalTmp = NULL; if (pThis->m_hpalBackGround) { hpalTmp = SelectPalette(hdc, pThis->m_hpalBackGround, FALSE); RealizePalette(hdc); } for (int left = 0; left <= rc.right; left += pThis->m_cxBackBmp) { for (int top = 0; top <= rc.bottom; top += pThis->m_cyBackBmp) { BitBlt(hdc, left, top, min(pThis->m_cxBackBmp, rc.right - left), min(pThis->m_cyBackBmp, rc.bottom - top), dc, 0, 0, SRCCOPY); } } if (hpalTmp) SelectPalette(hdc, hpalTmp, FALSE); return TRUE; } else if ( pThis->m_hbrBackGround ) { RECT rc; GetClipBox((HDC) wParam, &rc); FillRect((HDC) wParam, &rc, pThis->m_hbrBackGround); return TRUE; } else return DefWindowProc(hWnd, msg, wParam, lParam); default: return DefWindowProc(hWnd, msg, wParam, lParam); } return 0; } // // Something Ralphs code must use. Maybe this can go away ? // 09-Nov-1997 [ralphw] Nope, it can't go away. // void CVirtualListCtrl::PaintParamsSetup(COLORREF clrBackground, COLORREF clrForeground, LPCSTR pszBackBitmap) { if (clrBackground != -1 && clrForeground != -1) { HDC hdc = GetWindowDC(m_hWnd); // If the colors are the same, then ignore them both if (GetHighContrastFlag() || GetNearestColor(hdc, clrBackground) == GetNearestColor(hdc, clrForeground)) m_clrBackground = m_clrForeground = (COLORREF) -1; ReleaseDC(m_hWnd, hdc); } if (m_clrBackground != -1) m_hbrBackGround = CreateSolidBrush(m_clrBackground); if ( pszBackBitmap ) { char szBitmap[MAX_PATH]; if (ConvertToCacheFile(pszBackBitmap, szBitmap) && LoadGif(szBitmap, &m_hbmpBackGround, &m_hpalBackGround, NULL)) { BITMAP bmp; GetObject(m_hbmpBackGround, sizeof(BITMAP), &bmp); m_cxBackBmp = bmp.bmWidth; m_cyBackBmp = bmp.bmHeight; } } } HWND CVirtualListCtrl::CreateVlistbox(HWND hWndParent, RECT* prc) { WNDCLASS wc; WNDCLASSEX wci; if (! GetClassInfoEx(_Module.GetModuleInstance(), "hh_kwd_vlist", &wci) ) { wc.style = CS_DBLCLKS; // | CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = StaticWindowProc; wc.hIcon = NULL; wc.cbClsExtra = 0; wc.cbWndExtra = sizeof(CVirtualListCtrl*); wc.hInstance = _Module.GetModuleInstance(); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.lpszMenuName = NULL; wc.lpszClassName = "hh_kwd_vlist"; if (! RegisterClass(&wc) ) return FALSE; } CreateWindowEx(WS_EX_CLIENTEDGE | g_RTL_Style | (m_fBiDi ? WS_EX_LEFTSCROLLBAR : 0), "hh_kwd_vlist", NULL, WS_CHILD|WS_BORDER|WS_VISIBLE|WS_GROUP|WS_TABSTOP|WS_VSCROLL, prc->left, prc->top, (prc->right - prc->left), (prc->bottom - prc->top), hWndParent, (HMENU) IDC_KWD_VLIST, _Module.GetModuleInstance(), this); m_hWndParent = hWndParent; return m_hWnd; }