windows-nt/Source/XPSP1/NT/enduser/stuff/hhctrl/vlist.cpp
2020-09-26 16:20:57 +08:00

547 lines
15 KiB
C++

#include "header.h"
#include "vlist.h"
#include "cpaldc.h"
#include "hhctrl.h"
#include <winuser.h>
#include <commctrl.h>
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;
}