You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
536 lines
17 KiB
536 lines
17 KiB
/*******************************************************************************
|
|
*
|
|
* (C) COPYRIGHT MICROSOFT CORPORATION, 2000
|
|
*
|
|
* TITLE: CHKLISTV.CPP
|
|
*
|
|
* VERSION: 1.0
|
|
*
|
|
* AUTHOR: ShaunIv
|
|
*
|
|
* DATE: 11/13/2000
|
|
*
|
|
* DESCRIPTION: Listview with checkmarks
|
|
*
|
|
*******************************************************************************/
|
|
#include <windows.h>
|
|
#include <windowsx.h>
|
|
#include <commctrl.h>
|
|
#include <simarray.h>
|
|
#include <psutil.h>
|
|
#include <wiadebug.h>
|
|
#include "chklistv.h"
|
|
|
|
CCheckedListviewHandler::CCheckedListviewHandler(void)
|
|
: m_bFullImageHit(false),
|
|
m_hImageList(NULL),
|
|
m_nCheckedImageIndex(-1),
|
|
m_nUncheckedImageIndex(-1)
|
|
{
|
|
ZeroMemory(&m_sizeCheck,sizeof(m_sizeCheck));
|
|
CreateDefaultCheckBitmaps();
|
|
}
|
|
|
|
|
|
CCheckedListviewHandler::~CCheckedListviewHandler(void)
|
|
{
|
|
//
|
|
// Free all allocated memory
|
|
//
|
|
DestroyImageList();
|
|
}
|
|
|
|
HBITMAP CCheckedListviewHandler::CreateBitmap( int nWidth, int nHeight )
|
|
{
|
|
//
|
|
// Create a 24bit RGB DIB section of a given size
|
|
//
|
|
HBITMAP hBitmap = NULL;
|
|
HDC hDC = GetDC( NULL );
|
|
if (hDC)
|
|
{
|
|
BITMAPINFO BitmapInfo = {0};
|
|
BitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
BitmapInfo.bmiHeader.biWidth = nWidth;
|
|
BitmapInfo.bmiHeader.biHeight = nHeight;
|
|
BitmapInfo.bmiHeader.biPlanes = 1;
|
|
BitmapInfo.bmiHeader.biBitCount = 24;
|
|
BitmapInfo.bmiHeader.biCompression = BI_RGB;
|
|
|
|
PBYTE *pBits = NULL;
|
|
hBitmap = CreateDIBSection( hDC, &BitmapInfo, DIB_RGB_COLORS, (void**)&pBits, NULL, 0 );
|
|
ReleaseDC( NULL, hDC );
|
|
}
|
|
return hBitmap;
|
|
}
|
|
|
|
void CCheckedListviewHandler::DestroyImageList(void)
|
|
{
|
|
//
|
|
// Destroy the image list and initialize related variables
|
|
//
|
|
if (m_hImageList)
|
|
{
|
|
ImageList_Destroy( m_hImageList );
|
|
m_hImageList = NULL;
|
|
}
|
|
m_nCheckedImageIndex = m_nUncheckedImageIndex = -1;
|
|
m_sizeCheck.cx = m_sizeCheck.cy = 0;
|
|
}
|
|
|
|
|
|
bool CCheckedListviewHandler::ImagesValid(void)
|
|
{
|
|
//
|
|
// Make sure the images in the image list are valid
|
|
//
|
|
return (m_hImageList && m_nCheckedImageIndex >= 0 && m_nUncheckedImageIndex >= 0 && m_sizeCheck.cx && m_sizeCheck.cy);
|
|
}
|
|
|
|
void CCheckedListviewHandler::Attach( HWND hWnd )
|
|
{
|
|
if (m_WindowList.Find(hWnd) < 0)
|
|
{
|
|
m_WindowList.Append(hWnd);
|
|
}
|
|
}
|
|
|
|
void CCheckedListviewHandler::Detach( HWND hWnd )
|
|
{
|
|
int nIndex = m_WindowList.Find(hWnd);
|
|
if (nIndex >= 0)
|
|
{
|
|
m_WindowList.Delete( nIndex );
|
|
}
|
|
}
|
|
|
|
bool CCheckedListviewHandler::WindowInList( HWND hWnd )
|
|
{
|
|
return (m_WindowList.Find(hWnd) >= 0);
|
|
}
|
|
|
|
//
|
|
// Private helpers
|
|
//
|
|
BOOL CCheckedListviewHandler::InCheckBox( HWND hwndList, int nItem, const POINT &pt )
|
|
{
|
|
BOOL bResult = FALSE;
|
|
if (WindowInList(hwndList))
|
|
{
|
|
#if defined(DBG)
|
|
WIA_TRACE((TEXT("nItem: %d"), nItem ));
|
|
LVHITTESTINFO LvHitTestInfo = {0};
|
|
LvHitTestInfo.pt = pt;
|
|
ListView_SubItemHitTest( hwndList, &LvHitTestInfo );
|
|
WIA_TRACE((TEXT("LvHitTestInfo.iItem: %d"), LvHitTestInfo.iItem ));
|
|
#endif
|
|
RECT rcItem = {0};
|
|
if (ListView_GetItemRect( hwndList, nItem, &rcItem, LVIR_ICON ))
|
|
{
|
|
WIA_TRACE((TEXT("pt: (%d, %d)"), pt.x, pt.y ));
|
|
WIA_TRACE((TEXT("rcItem: (%d, %d), (%d, %d)"), rcItem.left, rcItem.top, rcItem.right, rcItem.bottom ));
|
|
rcItem.right -= c_sizeCheckMarginX;
|
|
rcItem.top += c_sizeCheckMarginY;
|
|
rcItem.left = rcItem.right - m_sizeCheck.cx;
|
|
rcItem.bottom = rcItem.top + m_sizeCheck.cy;
|
|
|
|
bResult = PtInRect( &rcItem, pt );
|
|
}
|
|
}
|
|
return bResult;
|
|
}
|
|
|
|
|
|
UINT CCheckedListviewHandler::GetItemCheckState( HWND hwndList, int nIndex )
|
|
{
|
|
UINT nResult = LVCHECKSTATE_NOCHECK;
|
|
|
|
NMGETCHECKSTATE NmGetCheckState = {0};
|
|
NmGetCheckState.hdr.hwndFrom = hwndList;
|
|
NmGetCheckState.hdr.idFrom = GetWindowLong( hwndList, GWL_ID );
|
|
NmGetCheckState.hdr.code = NM_GETCHECKSTATE;
|
|
NmGetCheckState.nItem = nIndex;
|
|
|
|
nResult = static_cast<UINT>(SendMessage( reinterpret_cast<HWND>(GetWindowLongPtr(hwndList,GWLP_HWNDPARENT)), WM_NOTIFY, GetWindowLong( hwndList, GWL_ID ), reinterpret_cast<LPARAM>(&NmGetCheckState) ) );
|
|
return nResult;
|
|
}
|
|
|
|
|
|
UINT CCheckedListviewHandler::SetItemCheckState( HWND hwndList, int nIndex, UINT nCheck )
|
|
{
|
|
UINT nResult = GetItemCheckState( hwndList, nIndex );
|
|
|
|
NMSETCHECKSTATE NmSetCheckState = {0};
|
|
NmSetCheckState.hdr.hwndFrom = hwndList;
|
|
NmSetCheckState.hdr.idFrom = GetWindowLong( hwndList, GWL_ID );
|
|
NmSetCheckState.hdr.code = NM_SETCHECKSTATE;
|
|
NmSetCheckState.nItem = nIndex;
|
|
NmSetCheckState.nCheck = nCheck;
|
|
|
|
SendMessage( reinterpret_cast<HWND>(GetWindowLongPtr(hwndList,GWLP_HWNDPARENT)), WM_NOTIFY, GetWindowLong( hwndList, GWL_ID ), reinterpret_cast<LPARAM>(&NmSetCheckState) );
|
|
return nResult;
|
|
}
|
|
|
|
|
|
int CCheckedListviewHandler::GetItemCheckBitmap( HWND hwndList, int nIndex )
|
|
{
|
|
int nResult = -1;
|
|
if (WindowInList(hwndList))
|
|
{
|
|
UINT nCheck = GetItemCheckState( hwndList, nIndex );
|
|
switch (nCheck)
|
|
{
|
|
case LVCHECKSTATE_CHECKED:
|
|
nResult = m_nCheckedImageIndex;
|
|
break;
|
|
|
|
case LVCHECKSTATE_UNCHECKED:
|
|
nResult = m_nUncheckedImageIndex;
|
|
break;
|
|
}
|
|
}
|
|
return nResult;
|
|
}
|
|
|
|
|
|
BOOL CCheckedListviewHandler::RealHandleListClick( WPARAM wParam, LPARAM lParam, bool bIgnoreHitArea )
|
|
{
|
|
BOOL bResult = FALSE;
|
|
NMITEMACTIVATE *pNmItemActivate = reinterpret_cast<NMITEMACTIVATE*>(lParam);
|
|
if (pNmItemActivate)
|
|
{
|
|
if (WindowInList(pNmItemActivate->hdr.hwndFrom))
|
|
{
|
|
if (bIgnoreHitArea || InCheckBox(pNmItemActivate->hdr.hwndFrom,pNmItemActivate->iItem,pNmItemActivate->ptAction))
|
|
{
|
|
UINT nCheck = GetItemCheckState( pNmItemActivate->hdr.hwndFrom, pNmItemActivate->iItem );
|
|
switch (nCheck)
|
|
{
|
|
case LVCHECKSTATE_UNCHECKED:
|
|
SetItemCheckState( pNmItemActivate->hdr.hwndFrom, pNmItemActivate->iItem, LVCHECKSTATE_CHECKED );
|
|
break;
|
|
|
|
case LVCHECKSTATE_CHECKED:
|
|
SetItemCheckState( pNmItemActivate->hdr.hwndFrom, pNmItemActivate->iItem, LVCHECKSTATE_UNCHECKED );
|
|
break;
|
|
}
|
|
}
|
|
bResult = TRUE;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
//
|
|
// Message handlers
|
|
//
|
|
BOOL CCheckedListviewHandler::HandleListClick( WPARAM wParam, LPARAM lParam )
|
|
{
|
|
return RealHandleListClick( wParam, lParam, m_bFullImageHit );
|
|
}
|
|
|
|
BOOL CCheckedListviewHandler::HandleListDblClk( WPARAM wParam, LPARAM lParam )
|
|
{
|
|
return RealHandleListClick( wParam, lParam, true );
|
|
}
|
|
|
|
BOOL CCheckedListviewHandler::HandleListKeyDown( WPARAM wParam, LPARAM lParam, LRESULT &lResult )
|
|
{
|
|
BOOL bHandled = FALSE;
|
|
NMLVKEYDOWN *pNmLvKeyDown = reinterpret_cast<NMLVKEYDOWN*>(lParam);
|
|
if (WindowInList(pNmLvKeyDown->hdr.hwndFrom))
|
|
{
|
|
lResult = 0;
|
|
bool bControl = (GetKeyState(VK_CONTROL) & 0x8000) != 0;
|
|
bool bShift = (GetKeyState(VK_SHIFT) & 0x8000) != 0;
|
|
bool bAlt = (GetKeyState(VK_MENU) & 0x8000) != 0;
|
|
if (pNmLvKeyDown->wVKey == VK_SPACE && !bControl && !bShift && !bAlt)
|
|
{
|
|
int nFocusedItem = ListView_GetNextItem( pNmLvKeyDown->hdr.hwndFrom, -1, LVNI_FOCUSED );
|
|
if (nFocusedItem >= 0)
|
|
{
|
|
UINT nCheckState = GetItemCheckState( pNmLvKeyDown->hdr.hwndFrom, nFocusedItem );
|
|
if (LVCHECKSTATE_CHECKED == nCheckState)
|
|
{
|
|
nCheckState = LVCHECKSTATE_UNCHECKED;
|
|
}
|
|
else if (LVCHECKSTATE_UNCHECKED == nCheckState)
|
|
{
|
|
nCheckState = LVCHECKSTATE_CHECKED;
|
|
}
|
|
if (nCheckState != LVCHECKSTATE_NOCHECK)
|
|
{
|
|
int nCurrItem = -1;
|
|
while (true)
|
|
{
|
|
nCurrItem = ListView_GetNextItem( pNmLvKeyDown->hdr.hwndFrom, nCurrItem, LVNI_SELECTED );
|
|
if (nCurrItem < 0)
|
|
{
|
|
break;
|
|
}
|
|
SetItemCheckState( pNmLvKeyDown->hdr.hwndFrom, nCurrItem, nCheckState );
|
|
}
|
|
}
|
|
}
|
|
lResult = TRUE;
|
|
bHandled = TRUE;
|
|
InvalidateRect( pNmLvKeyDown->hdr.hwndFrom, NULL, FALSE );
|
|
UpdateWindow( pNmLvKeyDown->hdr.hwndFrom );
|
|
}
|
|
}
|
|
return bHandled;
|
|
}
|
|
|
|
|
|
BOOL CCheckedListviewHandler::HandleListCustomDraw( WPARAM wParam, LPARAM lParam, LRESULT &lResult )
|
|
{
|
|
BOOL bHandled = FALSE;
|
|
NMLVCUSTOMDRAW *pNmCustomDraw = reinterpret_cast<NMLVCUSTOMDRAW*>(lParam);
|
|
if (pNmCustomDraw)
|
|
{
|
|
if (WindowInList(pNmCustomDraw->nmcd.hdr.hwndFrom))
|
|
{
|
|
lResult = CDRF_DODEFAULT;
|
|
#if defined(DUMP_NM_CUSTOMDRAW_MESSAGES)
|
|
DumpCustomDraw(lParam,TEXT("SysListView32"),CDDS_ITEMPOSTPAINT);
|
|
#endif
|
|
if (CDDS_PREPAINT == pNmCustomDraw->nmcd.dwDrawStage)
|
|
{
|
|
lResult = CDRF_NOTIFYITEMDRAW;
|
|
}
|
|
else if (CDDS_ITEMPREPAINT == pNmCustomDraw->nmcd.dwDrawStage)
|
|
{
|
|
lResult = CDRF_NOTIFYPOSTPAINT|CDRF_NOTIFYSUBITEMDRAW;
|
|
}
|
|
else if (CDDS_ITEMPOSTPAINT == pNmCustomDraw->nmcd.dwDrawStage)
|
|
{
|
|
int nImageListIndex = GetItemCheckBitmap( pNmCustomDraw->nmcd.hdr.hwndFrom, static_cast<int>(pNmCustomDraw->nmcd.dwItemSpec) );
|
|
if (nImageListIndex >= 0)
|
|
{
|
|
RECT rcItem = {0};
|
|
if (ListView_GetItemRect( pNmCustomDraw->nmcd.hdr.hwndFrom, pNmCustomDraw->nmcd.dwItemSpec, &rcItem, LVIR_ICON ))
|
|
{
|
|
ImageList_Draw( m_hImageList, nImageListIndex, pNmCustomDraw->nmcd.hdc, rcItem.right - m_sizeCheck.cx - c_sizeCheckMarginX, rcItem.top + c_sizeCheckMarginY, ILD_NORMAL );
|
|
lResult = CDRF_SKIPDEFAULT;
|
|
}
|
|
}
|
|
}
|
|
bHandled = TRUE;
|
|
}
|
|
}
|
|
return bHandled;
|
|
}
|
|
|
|
void CCheckedListviewHandler::Select( HWND hwndList, int nIndex, UINT nSelect )
|
|
{
|
|
if (WindowInList(hwndList))
|
|
{
|
|
//
|
|
// -1 means all images
|
|
//
|
|
if (nIndex < 0)
|
|
{
|
|
for (int i=0;i<ListView_GetItemCount(hwndList);i++)
|
|
{
|
|
SetItemCheckState(hwndList,i,nSelect);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetItemCheckState(hwndList,nIndex,nSelect);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
bool CCheckedListviewHandler::FullImageHit(void) const
|
|
{
|
|
return m_bFullImageHit;
|
|
}
|
|
|
|
void CCheckedListviewHandler::FullImageHit( bool bFullImageHit )
|
|
{
|
|
m_bFullImageHit = bFullImageHit;
|
|
}
|
|
|
|
|
|
bool CCheckedListviewHandler::CreateDefaultCheckBitmaps(void)
|
|
{
|
|
bool bResult = false;
|
|
|
|
//
|
|
// Get the proper size for the checkmarks
|
|
//
|
|
int nWidth = GetSystemMetrics( SM_CXMENUCHECK );
|
|
int nHeight = GetSystemMetrics( SM_CXMENUCHECK );
|
|
|
|
//
|
|
// Make sure they are valid sizes
|
|
//
|
|
if (nWidth && nHeight)
|
|
{
|
|
//
|
|
// Create the bitmaps and make sure they are valid
|
|
//
|
|
HBITMAP hBitmapChecked = CreateBitmap( nWidth+c_nCheckmarkBorder*2, nHeight+c_nCheckmarkBorder*2 );
|
|
HBITMAP hBitmapUnchecked = CreateBitmap( nWidth+c_nCheckmarkBorder*2, nHeight+c_nCheckmarkBorder*2 );
|
|
if (hBitmapChecked && hBitmapUnchecked)
|
|
{
|
|
//
|
|
// Get the desktop DC
|
|
//
|
|
HDC hDC = GetDC( NULL );
|
|
if (hDC)
|
|
{
|
|
//
|
|
// Create a memory DC
|
|
//
|
|
HDC hMemDC = CreateCompatibleDC( hDC );
|
|
if (hMemDC)
|
|
{
|
|
//
|
|
// This is the rect that contains the image + the margin
|
|
//
|
|
RECT rcEntireBitmap = {0,0,nWidth+c_nCheckmarkBorder*2, nHeight+c_nCheckmarkBorder*2};
|
|
|
|
//
|
|
// This is the rect that contains only the image
|
|
//
|
|
RECT rcControlBitmap = {c_nCheckmarkBorder,c_nCheckmarkBorder,nWidth+c_nCheckmarkBorder, nHeight+c_nCheckmarkBorder};
|
|
|
|
//
|
|
// Paint the checked bitmap
|
|
//
|
|
HBITMAP hOldBitmap = SelectBitmap( hMemDC, hBitmapChecked );
|
|
FillRect( hMemDC, &rcEntireBitmap, GetSysColorBrush( COLOR_WINDOW ) );
|
|
DrawFrameControl( hMemDC, &rcControlBitmap, DFC_BUTTON, DFCS_BUTTONCHECK|DFCS_CHECKED|DFCS_FLAT );
|
|
|
|
//
|
|
// Paint the unchecked bitmap
|
|
//
|
|
SelectBitmap( hMemDC, hBitmapUnchecked );
|
|
FillRect( hMemDC, &rcEntireBitmap, GetSysColorBrush( COLOR_WINDOW ) );
|
|
DrawFrameControl( hMemDC, &rcControlBitmap, DFC_BUTTON, DFCS_BUTTONCHECK|DFCS_FLAT );
|
|
|
|
//
|
|
// Restore and delete the memory DC
|
|
//
|
|
SelectBitmap( hMemDC, hOldBitmap );
|
|
DeleteDC( hMemDC );
|
|
|
|
//
|
|
// Save the images
|
|
//
|
|
bResult = SetCheckboxImages( hBitmapChecked, hBitmapUnchecked );
|
|
|
|
//
|
|
// The images are in the image list now, so discard them
|
|
//
|
|
DeleteBitmap(hBitmapChecked);
|
|
DeleteBitmap(hBitmapUnchecked);
|
|
}
|
|
ReleaseDC( NULL, hDC );
|
|
}
|
|
}
|
|
}
|
|
return bResult;
|
|
}
|
|
|
|
|
|
bool CCheckedListviewHandler::SetCheckboxImages( HBITMAP hChecked, HBITMAP hUnchecked )
|
|
{
|
|
DestroyImageList();
|
|
|
|
//
|
|
// Find out the size of the bitmaps and make sure they are the same.
|
|
//
|
|
SIZE sizeChecked = {0};
|
|
if (PrintScanUtil::GetBitmapSize( hChecked, sizeChecked ))
|
|
{
|
|
SIZE sizeUnchecked = {0};
|
|
if (PrintScanUtil::GetBitmapSize( hUnchecked, sizeUnchecked ))
|
|
{
|
|
if (sizeChecked.cx == sizeUnchecked.cx && sizeChecked.cy == sizeUnchecked.cy)
|
|
{
|
|
//
|
|
// Save the size
|
|
//
|
|
m_sizeCheck.cx = sizeChecked.cx;
|
|
m_sizeCheck.cy = sizeChecked.cy;
|
|
|
|
//
|
|
// Create the image list to hold the checkboxes
|
|
//
|
|
m_hImageList = ImageList_Create( m_sizeCheck.cx, m_sizeCheck.cy, ILC_COLOR24, 2, 2 );
|
|
if (m_hImageList)
|
|
{
|
|
//
|
|
// Save the indices of the images
|
|
//
|
|
m_nCheckedImageIndex = ImageList_Add( m_hImageList, hChecked, NULL );
|
|
m_nUncheckedImageIndex = ImageList_Add( m_hImageList, hUnchecked, NULL );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the images aren't valid, clean up
|
|
//
|
|
bool bResult = ImagesValid();
|
|
if (!bResult)
|
|
{
|
|
DestroyImageList();
|
|
}
|
|
return bResult;
|
|
}
|
|
|
|
bool CCheckedListviewHandler::SetCheckboxImages( HICON hChecked, HICON hUnchecked )
|
|
{
|
|
DestroyImageList();
|
|
|
|
//
|
|
// Find out the size of the icons and make sure they are the same.
|
|
//
|
|
SIZE sizeChecked = {0};
|
|
if (PrintScanUtil::GetIconSize( hChecked, sizeChecked ))
|
|
{
|
|
SIZE sizeUnchecked = {0};
|
|
if (PrintScanUtil::GetIconSize( hUnchecked, sizeUnchecked ))
|
|
{
|
|
if (sizeChecked.cx == sizeUnchecked.cx && sizeChecked.cy == sizeUnchecked.cy)
|
|
{
|
|
//
|
|
// Save the size
|
|
//
|
|
m_sizeCheck.cx = sizeChecked.cx;
|
|
m_sizeCheck.cy = sizeChecked.cy;
|
|
|
|
//
|
|
// Create the image list to hold the checkboxes
|
|
//
|
|
m_hImageList = ImageList_Create( m_sizeCheck.cx, m_sizeCheck.cy, ILC_COLOR24|ILC_MASK, 2, 2 );
|
|
if (m_hImageList)
|
|
{
|
|
//
|
|
// Save the indices of the images
|
|
//
|
|
m_nCheckedImageIndex = ImageList_AddIcon( m_hImageList, hChecked );
|
|
m_nUncheckedImageIndex = ImageList_AddIcon( m_hImageList, hUnchecked );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the images aren't valid, clean up
|
|
//
|
|
bool bResult = ImagesValid();
|
|
if (!bResult)
|
|
{
|
|
DestroyImageList();
|
|
}
|
|
return bResult;
|
|
}
|
|
|