547 lines
15 KiB
C++
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;
|
|
}
|