1289 lines
38 KiB
C++
1289 lines
38 KiB
C++
|
/**********************************************************************/
|
||
|
/** Microsoft Windows/NT **/
|
||
|
/** Copyright(c) Microsoft Corp., 1991-2001 **/
|
||
|
/**********************************************************************/
|
||
|
|
||
|
/*
|
||
|
|
||
|
CHKLIST.CPP
|
||
|
|
||
|
This file contains the implementation of the CheckList control.
|
||
|
|
||
|
*/
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
#include <windowsx.h>
|
||
|
#include "chklist.h"
|
||
|
#include "debug.h"
|
||
|
#include "util.h"
|
||
|
|
||
|
//
|
||
|
// Text and Background colors
|
||
|
//
|
||
|
#define TEXT_COLOR COLOR_WINDOWTEXT
|
||
|
#define BK_COLOR COLOR_WINDOW
|
||
|
|
||
|
//
|
||
|
// Default dimensions for child controls. All are in dialog units.
|
||
|
// Currently only the column width is user-adjustable (via the
|
||
|
// CLM_SETCOLUMNWIDTH message).
|
||
|
//
|
||
|
#define DEFAULT_COLUMN_WIDTH 32
|
||
|
#define DEFAULT_CHECK_WIDTH 9
|
||
|
#define DEFAULT_HORZ_SPACE 7
|
||
|
#define DEFAULT_VERTICAL_SPACE 3
|
||
|
#define DEFAULT_ITEM_HEIGHT 8
|
||
|
|
||
|
//
|
||
|
// 16 bits are used for the control ID's, divided into n bits for
|
||
|
// the subitem (least significant) and 16-n bits for the item index.
|
||
|
//
|
||
|
// ID_SUBITEM_BITS can be adjusted to control the maximum number of
|
||
|
// items and subitems. For example, to allow up to 7 subitems and 8k
|
||
|
// items, set ID_SUBITEM_BITS to 3.
|
||
|
//
|
||
|
|
||
|
// Use the low 2 bits for the subitem index, the rest for the item index.
|
||
|
// (4 subitems max, 16k items max)
|
||
|
#define ID_SUBITEM_BITS 2
|
||
|
|
||
|
#define ID_SUBITEM_MASK ((1 << ID_SUBITEM_BITS) - 1)
|
||
|
#define GET_ITEM(id) ((id) >> ID_SUBITEM_BITS)
|
||
|
#define GET_SUBITEM(id) ((id) & ID_SUBITEM_MASK)
|
||
|
|
||
|
#define MAKE_CTRL_ID(i, s) (0xffff & (((i) << ID_SUBITEM_BITS) | ((s) & ID_SUBITEM_MASK)))
|
||
|
#define MAKE_LABEL_ID(i) MAKE_CTRL_ID(i, 0)
|
||
|
// Note that the subitem (column) index is one-based for the checkboxes
|
||
|
// (the zero column is the label). The item (row) index is zero-based.
|
||
|
|
||
|
#define MAX_CHECK_COLUMNS ID_SUBITEM_MASK
|
||
|
|
||
|
|
||
|
typedef struct _USERDATA_STRUCT_LABEL
|
||
|
{
|
||
|
LPARAM lParam;
|
||
|
int nLabelHeight;
|
||
|
int itemIndex;
|
||
|
} USERDATA_STRUCT_LABEL, *LPUSERDATA_STRUCT_LABEL;
|
||
|
|
||
|
class CCheckList
|
||
|
{
|
||
|
private:
|
||
|
LONG m_cItems;
|
||
|
LONG m_cSubItems;
|
||
|
RECT m_rcItemLabel;
|
||
|
LONG m_nCheckPos[MAX_CHECK_COLUMNS];
|
||
|
LONG m_cxCheckBox;
|
||
|
LONG m_cxCheckColumn;
|
||
|
|
||
|
int m_nDefaultVerticalSpace;
|
||
|
int m_nDefaultItemHeight;
|
||
|
int m_nNewItemYPos;
|
||
|
|
||
|
HWND m_hwndCheckFocus;
|
||
|
|
||
|
BOOL m_fInMessageEnable;
|
||
|
|
||
|
int m_cWheelDelta;
|
||
|
static UINT g_ucScrollLines;
|
||
|
|
||
|
private:
|
||
|
CCheckList(HWND hWnd, LPCREATESTRUCT lpcs);
|
||
|
|
||
|
LRESULT MsgCommand(HWND hWnd, WORD idCmd, WORD wNotify, HWND hwndCtrl);
|
||
|
void MsgPaint(HWND hWnd, HDC hdc);
|
||
|
void MsgVScroll(HWND hWnd, int nCode, int nPos);
|
||
|
void MsgMouseWheel(HWND hWnd, WORD fwFlags, int zDelta);
|
||
|
void MsgButtonDown(HWND hWnd, WPARAM fwFlags, int xPos, int yPos);
|
||
|
void MsgEnable(HWND hWnd, BOOL fEnabled);
|
||
|
void MsgSize(HWND hWnd, DWORD dwSizeType, LONG nWidth, LONG nHeight);
|
||
|
|
||
|
LONG AddItem(HWND hWnd, LPCTSTR pszLabel, LPARAM lParam);
|
||
|
void SetState(HWND hWnd, WORD iItem, WORD iSubItem, LONG lState);
|
||
|
LONG GetState(HWND hWnd, WORD iItem, WORD iSubItem);
|
||
|
void SetColumnWidth(HWND hWnd, LONG cxDialog, LONG cxColumn);
|
||
|
void ResetContent(HWND hWnd);
|
||
|
LONG GetVisibleCount(HWND hWnd);
|
||
|
LONG GetTopIndex(HWND hWnd, LONG *pnAmountObscured = NULL);
|
||
|
void SetTopIndex(HWND hWnd, LONG nIndex);
|
||
|
void EnsureVisible(HWND hWnd, LONG nIndex);
|
||
|
void DrawCheckFocusRect(HWND hWnd, HWND hwndCheck, BOOL fDraw);
|
||
|
|
||
|
public:
|
||
|
HWND m_hWnd;
|
||
|
static LRESULT CALLBACK WindowProc(HWND hWnd,
|
||
|
UINT uMsg,
|
||
|
WPARAM wParam,
|
||
|
LPARAM lParam);
|
||
|
};
|
||
|
|
||
|
BOOL RegisterCheckListWndClass(void)
|
||
|
{
|
||
|
WNDCLASS wc;
|
||
|
|
||
|
wc.style = 0;
|
||
|
wc.lpfnWndProc = CCheckList::WindowProc;
|
||
|
wc.cbClsExtra = 0;
|
||
|
wc.cbWndExtra = 0;
|
||
|
AFX_MANAGE_STATE(AfxGetStaticModuleState()); // Required for AfxGetInstanceHandle()
|
||
|
wc.hInstance = AfxGetInstanceHandle(); //hModule;
|
||
|
wc.hIcon = NULL;
|
||
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||
|
wc.hbrBackground = (HBRUSH)(BK_COLOR+1);
|
||
|
wc.lpszMenuName = NULL;
|
||
|
wc.lpszClassName = TEXT(WC_CHECKLIST);
|
||
|
|
||
|
return (BOOL)RegisterClass(&wc);
|
||
|
}
|
||
|
|
||
|
|
||
|
UINT CCheckList::g_ucScrollLines = (UINT)-1;
|
||
|
|
||
|
|
||
|
CCheckList::CCheckList(HWND hWnd, LPCREATESTRUCT lpcs)
|
||
|
: m_cItems(0), m_hwndCheckFocus(NULL), m_fInMessageEnable(FALSE), m_cWheelDelta(0)
|
||
|
{
|
||
|
TraceEnter(TRACE_CHECKLIST, "CCheckList::CCheckList");
|
||
|
TraceAssert(hWnd != NULL);
|
||
|
TraceAssert(lpcs != NULL);
|
||
|
|
||
|
m_hWnd = hWnd;
|
||
|
//
|
||
|
// Get number of check columns
|
||
|
//
|
||
|
m_cSubItems = lpcs->style & CLS_CHECKMASK;
|
||
|
|
||
|
// for wsecedit only
|
||
|
if ( m_cSubItems > 3 ) {
|
||
|
m_cSubItems = 3;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Convert default coordinates from dialog units to pixels
|
||
|
//
|
||
|
RECT rc;
|
||
|
rc.left = DEFAULT_CHECK_WIDTH;
|
||
|
rc.right = DEFAULT_COLUMN_WIDTH;
|
||
|
rc.top = rc.bottom = 0;
|
||
|
MapDialogRect(lpcs->hwndParent, &rc);
|
||
|
|
||
|
// Save the converted values
|
||
|
m_cxCheckBox = rc.left;
|
||
|
m_cxCheckColumn = rc.right;
|
||
|
|
||
|
rc.left = DEFAULT_HORZ_SPACE;
|
||
|
rc.top = DEFAULT_VERTICAL_SPACE;
|
||
|
rc.right = 10; // bogus (unused)
|
||
|
rc.bottom = DEFAULT_VERTICAL_SPACE + DEFAULT_ITEM_HEIGHT;
|
||
|
MapDialogRect(lpcs->hwndParent, &rc);
|
||
|
|
||
|
// Save the converted values
|
||
|
m_rcItemLabel = rc;
|
||
|
|
||
|
m_nDefaultVerticalSpace = rc.top;
|
||
|
m_nDefaultItemHeight = rc.bottom - rc.top;
|
||
|
m_nNewItemYPos = rc.top;
|
||
|
|
||
|
//
|
||
|
// Get info for mouse wheel scrolling
|
||
|
//
|
||
|
if ((UINT)-1 == g_ucScrollLines)
|
||
|
{
|
||
|
g_ucScrollLines = 3; // default
|
||
|
SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &g_ucScrollLines, 0);
|
||
|
}
|
||
|
|
||
|
TraceLeaveVoid();
|
||
|
}
|
||
|
|
||
|
|
||
|
LRESULT
|
||
|
CCheckList::MsgCommand(HWND hWnd, WORD idCmd, WORD wNotify, HWND hwndCtrl)
|
||
|
{
|
||
|
TraceEnter(TRACE_CHECKLIST, "CCheckList::MsgCommand");
|
||
|
|
||
|
// Should only get notifications from visible, enabled, check boxes
|
||
|
TraceAssert(GET_ITEM(idCmd) < m_cItems);
|
||
|
TraceAssert(0 < GET_SUBITEM(idCmd) && GET_SUBITEM(idCmd) <= m_cSubItems);
|
||
|
TraceAssert(hwndCtrl && IsWindowEnabled(hwndCtrl));
|
||
|
|
||
|
switch (wNotify)
|
||
|
{
|
||
|
case EN_SETFOCUS:
|
||
|
{
|
||
|
// Make the focus go to one of the checkboxes
|
||
|
POINT pt;
|
||
|
DWORD dwPos = GetMessagePos();
|
||
|
pt.x = GET_X_LPARAM(dwPos);
|
||
|
pt.y = GET_Y_LPARAM(dwPos);
|
||
|
MapWindowPoints(NULL, hWnd, &pt, 1);
|
||
|
MsgButtonDown(hWnd, 0, pt.x, pt.y);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case BN_CLICKED:
|
||
|
{
|
||
|
LPUSERDATA_STRUCT_LABEL lpUserData;
|
||
|
NM_CHECKLIST nmc;
|
||
|
nmc.hdr.hwndFrom = hWnd;
|
||
|
nmc.hdr.idFrom = GetDlgCtrlID(hWnd);
|
||
|
nmc.hdr.code = CLN_CLICK;
|
||
|
nmc.iItem = GET_ITEM(idCmd);
|
||
|
nmc.iSubItem = GET_SUBITEM(idCmd);
|
||
|
nmc.dwState = (DWORD)SendMessage(hwndCtrl, BM_GETCHECK, 0, 0);
|
||
|
if (!IsWindowEnabled(hwndCtrl))
|
||
|
nmc.dwState |= CLST_DISABLED;
|
||
|
lpUserData = (LPUSERDATA_STRUCT_LABEL)
|
||
|
GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID(nmc.iItem)),
|
||
|
GWLP_USERDATA);
|
||
|
nmc.dwItemData = lpUserData->lParam;
|
||
|
|
||
|
SendMessage(GetParent(hWnd),
|
||
|
WM_NOTIFY,
|
||
|
nmc.hdr.idFrom,
|
||
|
(LPARAM)&nmc);
|
||
|
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case BN_SETFOCUS:
|
||
|
if (GetFocus() != hwndCtrl)
|
||
|
{
|
||
|
// This causes another BN_SETFOCUS
|
||
|
SetFocus(hwndCtrl);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (m_hwndCheckFocus != hwndCtrl) // Has the focus moved?
|
||
|
{
|
||
|
// Remember where the focus is
|
||
|
m_hwndCheckFocus = hwndCtrl;
|
||
|
|
||
|
// Make sure the row is scrolled into view
|
||
|
EnsureVisible(hWnd, GET_ITEM(idCmd));
|
||
|
}
|
||
|
// Always draw the focus rect
|
||
|
DrawCheckFocusRect(hWnd, hwndCtrl, TRUE);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case BN_KILLFOCUS:
|
||
|
// Remove the focus rect
|
||
|
m_hwndCheckFocus = NULL;
|
||
|
DrawCheckFocusRect(hWnd, hwndCtrl, FALSE);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
TraceLeaveValue(0);
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
CCheckList::MsgPaint(HWND hWnd, HDC hdc)
|
||
|
{
|
||
|
if (hdc == NULL && m_hwndCheckFocus != NULL)
|
||
|
{
|
||
|
// This will cause a focus rect to be drawn after the window and
|
||
|
// all checkboxes have been painted.
|
||
|
PostMessage(hWnd,
|
||
|
WM_COMMAND,
|
||
|
GET_WM_COMMAND_MPS(GetDlgCtrlID(m_hwndCheckFocus), m_hwndCheckFocus, BN_SETFOCUS));
|
||
|
}
|
||
|
|
||
|
// Default paint
|
||
|
DefWindowProc(hWnd, WM_PAINT, (WPARAM)hdc, 0);
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
CCheckList::MsgVScroll(HWND hWnd, int nCode, int nPos)
|
||
|
{
|
||
|
UINT cScrollUnitsPerLine;
|
||
|
SCROLLINFO si;
|
||
|
si.cbSize = sizeof(si);
|
||
|
si.fMask = SIF_ALL;
|
||
|
|
||
|
if (!GetScrollInfo(hWnd, SB_VERT, &si))
|
||
|
return;
|
||
|
|
||
|
cScrollUnitsPerLine = m_rcItemLabel.bottom;
|
||
|
|
||
|
// One page is always visible, so adjust the range to a more useful value
|
||
|
si.nMax -= si.nPage - 1;
|
||
|
|
||
|
switch (nCode)
|
||
|
{
|
||
|
case SB_LINEUP:
|
||
|
// "line" is the height of one item (includes the space in between)
|
||
|
nPos = si.nPos - cScrollUnitsPerLine;
|
||
|
break;
|
||
|
|
||
|
case SB_LINEDOWN:
|
||
|
nPos = si.nPos + cScrollUnitsPerLine;
|
||
|
break;
|
||
|
|
||
|
case SB_PAGEUP:
|
||
|
nPos = si.nPos - si.nPage;
|
||
|
break;
|
||
|
|
||
|
case SB_PAGEDOWN:
|
||
|
nPos = si.nPos + si.nPage;
|
||
|
break;
|
||
|
|
||
|
case SB_TOP:
|
||
|
nPos = si.nMin;
|
||
|
break;
|
||
|
|
||
|
case SB_BOTTOM:
|
||
|
nPos = si.nMax;
|
||
|
break;
|
||
|
|
||
|
case SB_ENDSCROLL:
|
||
|
nPos = si.nPos; // don't go anywhere
|
||
|
break;
|
||
|
|
||
|
case SB_THUMBTRACK:
|
||
|
// Do nothing here to allow tracking
|
||
|
// nPos = si.nPos; // Do this to prevent tracking
|
||
|
case SB_THUMBPOSITION:
|
||
|
// nothing to do here... nPos is passed in
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Make sure the new position is within the range
|
||
|
if (nPos < si.nMin)
|
||
|
nPos = si.nMin;
|
||
|
else if (nPos > si.nMax)
|
||
|
nPos = si.nMax;
|
||
|
|
||
|
if (nPos != si.nPos) // are we moving?
|
||
|
{
|
||
|
SetScrollPos(hWnd, SB_VERT, nPos, TRUE);
|
||
|
ScrollWindow(hWnd, 0, si.nPos - nPos, NULL, NULL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
CCheckList::MsgMouseWheel(HWND hWnd, WORD fwFlags, int iWheelDelta)
|
||
|
{
|
||
|
int cDetants;
|
||
|
|
||
|
if ((fwFlags & (MK_SHIFT | MK_CONTROL)) || 0 == g_ucScrollLines)
|
||
|
return;
|
||
|
|
||
|
TraceEnter(TRACE_CHECKLIST, "CCheckList::MsgMouseWheel");
|
||
|
|
||
|
// Update count of scroll amount
|
||
|
m_cWheelDelta -= iWheelDelta;
|
||
|
cDetants = m_cWheelDelta / WHEEL_DELTA;
|
||
|
if (0 == cDetants)
|
||
|
TraceLeaveVoid();
|
||
|
m_cWheelDelta %= WHEEL_DELTA;
|
||
|
|
||
|
if (WS_VSCROLL & GetWindowLong(hWnd, GWL_STYLE))
|
||
|
{
|
||
|
SCROLLINFO si;
|
||
|
UINT cScrollUnitsPerLine;
|
||
|
UINT cLinesPerPage;
|
||
|
UINT cLinesPerDetant;
|
||
|
|
||
|
// Get the scroll amount of one line
|
||
|
cScrollUnitsPerLine = m_rcItemLabel.bottom;
|
||
|
TraceAssert(cScrollUnitsPerLine > 0);
|
||
|
|
||
|
si.cbSize = sizeof(SCROLLINFO);
|
||
|
si.fMask = SIF_PAGE | SIF_POS;
|
||
|
if (!GetScrollInfo(hWnd, SB_VERT, &si))
|
||
|
TraceLeaveVoid();
|
||
|
|
||
|
// The size of a page is at least one line, and
|
||
|
// leaves one line of overlap
|
||
|
cLinesPerPage = (si.nPage - cScrollUnitsPerLine) / cScrollUnitsPerLine;
|
||
|
cLinesPerPage = max(1, cLinesPerPage);
|
||
|
|
||
|
// Don't scroll more than one page per detant
|
||
|
cLinesPerDetant = min(cLinesPerPage, g_ucScrollLines);
|
||
|
|
||
|
si.nPos += cDetants * cLinesPerDetant * cScrollUnitsPerLine;
|
||
|
|
||
|
MsgVScroll(hWnd, SB_THUMBTRACK, si.nPos);
|
||
|
}
|
||
|
TraceLeaveVoid();
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
CCheckList::MsgButtonDown(HWND hWnd, WPARAM /*fwFlags*/, int xPos, int yPos)
|
||
|
{
|
||
|
LONG nItemIndex;
|
||
|
HWND hwndCheck;
|
||
|
RECT rc;
|
||
|
|
||
|
// Get position of the top visible item in client coords
|
||
|
nItemIndex = GetTopIndex(hWnd);
|
||
|
if (nItemIndex == -1)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
hwndCheck = GetDlgItem(hWnd, MAKE_CTRL_ID(nItemIndex, 0));
|
||
|
GetWindowRect(hwndCheck, &rc);
|
||
|
MapWindowPoints(NULL, hWnd, (LPPOINT)&rc, 2);
|
||
|
|
||
|
// Find nearest item
|
||
|
if( hWnd == m_hWnd ) //Raid #387542, 5/9/2001
|
||
|
{
|
||
|
POINT pos = {xPos,yPos};
|
||
|
HWND ChildhWnd = ::ChildWindowFromPointEx(hWnd, pos, CWP_SKIPINVISIBLE|CWP_SKIPDISABLED);
|
||
|
if( ChildhWnd )
|
||
|
{
|
||
|
LPUSERDATA_STRUCT_LABEL pUserData = (LPUSERDATA_STRUCT_LABEL)GetWindowLongPtr(ChildhWnd, GWLP_USERDATA);
|
||
|
if( pUserData )
|
||
|
{
|
||
|
nItemIndex = pUserData->itemIndex;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Set focus to first subitem that is enabled
|
||
|
for (LONG j = 1; j <= m_cSubItems; j++)
|
||
|
{
|
||
|
int id = MAKE_CTRL_ID(nItemIndex, j);
|
||
|
HWND hwndCheck = GetDlgItem(hWnd, id);
|
||
|
if (IsWindowEnabled(hwndCheck))
|
||
|
{
|
||
|
// Don't just SetFocus here. We sometimes call this during
|
||
|
// EN_SETFOCUS, and USER doesn't like it when you mess with
|
||
|
// focus during a focus change.
|
||
|
//
|
||
|
//SetFocus(hwndCheck);
|
||
|
PostMessage(hWnd,
|
||
|
WM_COMMAND,
|
||
|
GET_WM_COMMAND_MPS(id, hwndCheck, BN_SETFOCUS));
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
CCheckList::MsgEnable(HWND hWnd, BOOL fEnabled)
|
||
|
{
|
||
|
HWND hwndCurrentCheck;
|
||
|
BOOL fCheckEnabled;
|
||
|
|
||
|
if (!m_fInMessageEnable)
|
||
|
{
|
||
|
m_fInMessageEnable = TRUE;
|
||
|
for (LONG i = 0; i < m_cItems; i++)
|
||
|
{
|
||
|
for (LONG j = 1; j <= m_cSubItems; j++)
|
||
|
{
|
||
|
hwndCurrentCheck = GetDlgItem(hWnd, MAKE_CTRL_ID(i, j));
|
||
|
fCheckEnabled = (BOOL) GetWindowLongPtr(hwndCurrentCheck, GWLP_USERDATA);
|
||
|
|
||
|
//
|
||
|
// If the user of the checklist control is disabling the control
|
||
|
// altogether, or the current checkbox has been disabled singularly
|
||
|
// then disable the checkbox
|
||
|
//
|
||
|
if (!fEnabled || !fCheckEnabled)
|
||
|
{
|
||
|
EnableWindow(hwndCurrentCheck, FALSE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
EnableWindow(hwndCurrentCheck, TRUE);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// Note that the main chklist window must remain enabled
|
||
|
// for scrolling to work while "disabled".
|
||
|
if (!fEnabled)
|
||
|
EnableWindow(hWnd, TRUE);
|
||
|
|
||
|
m_fInMessageEnable = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
CCheckList::MsgSize(HWND hWnd, DWORD dwSizeType, LONG nWidth, LONG nHeight)
|
||
|
{
|
||
|
TraceEnter(TRACE_CHECKLIST, "CCheckList::MsgSize");
|
||
|
TraceAssert(hWnd != NULL);
|
||
|
|
||
|
if (dwSizeType == SIZE_RESTORED)
|
||
|
{
|
||
|
RECT rc;
|
||
|
SCROLLINFO si;
|
||
|
|
||
|
si.cbSize = sizeof(si);
|
||
|
si.fMask = SIF_RANGE | SIF_PAGE;
|
||
|
si.nMin = 0;
|
||
|
si.nMax = m_nNewItemYPos - 1;
|
||
|
si.nPage = nHeight;
|
||
|
|
||
|
SetScrollInfo(hWnd, SB_VERT, &si, FALSE);
|
||
|
|
||
|
// Don't trust the width value passed in, since SetScrollInfo may
|
||
|
// affect it if the scroll bar is turning on or off.
|
||
|
GetClientRect(hWnd, &rc);
|
||
|
nWidth = rc.right;
|
||
|
|
||
|
// If the scrollbar is turned on, artificially bump up the width
|
||
|
// by the width of the scrollbar, so the boxes don't jump to the left
|
||
|
// when we have a scrollbar.
|
||
|
if ((UINT)si.nMax >= si.nPage)
|
||
|
nWidth += GetSystemMetrics(SM_CYHSCROLL);
|
||
|
|
||
|
SetColumnWidth(hWnd, nWidth, m_cxCheckColumn);
|
||
|
}
|
||
|
|
||
|
TraceLeaveVoid();
|
||
|
}
|
||
|
|
||
|
LONG CCheckList::AddItem(HWND hWnd, LPCTSTR pszLabel, LPARAM lParam)
|
||
|
{
|
||
|
HWND hwndPrev = 0;
|
||
|
LPUSERDATA_STRUCT_LABEL lpUserData = 0;
|
||
|
|
||
|
TraceEnter(TRACE_CHECKLIST, "CCheckList::AddItem");
|
||
|
TraceAssert(hWnd != NULL);
|
||
|
TraceAssert(pszLabel != NULL && !IsBadStringPtr(pszLabel, MAX_PATH));
|
||
|
if ( !hWnd || !pszLabel || IsBadStringPtr(pszLabel, MAX_PATH) )
|
||
|
return -1;
|
||
|
|
||
|
lpUserData = new (USERDATA_STRUCT_LABEL);
|
||
|
if ( lpUserData )
|
||
|
{
|
||
|
SCROLLINFO si;
|
||
|
si.cbSize = sizeof(si);
|
||
|
si.fMask = SIF_POS;
|
||
|
si.nPos = 0;
|
||
|
GetScrollInfo(hWnd, SB_VERT, &si);
|
||
|
|
||
|
// Set the initial label height extra big so the control can wrap the text,
|
||
|
// then reset it after creating the control.
|
||
|
RECT rc;
|
||
|
GetClientRect(hWnd, &rc);
|
||
|
LONG nLabelHeight = rc.bottom;
|
||
|
|
||
|
AFX_MANAGE_STATE(AfxGetStaticModuleState()); // Required for AfxGetInstanceHandle()
|
||
|
HMODULE hModule = AfxGetInstanceHandle();
|
||
|
|
||
|
// Create a new label control
|
||
|
HWND hwndNew = CreateWindowEx(WS_EX_NOPARENTNOTIFY,
|
||
|
TEXT("edit"),
|
||
|
pszLabel,
|
||
|
WS_CHILD | WS_VISIBLE | WS_GROUP | ES_MULTILINE | ES_READONLY | ES_LEFT,// | WS_GROUP,
|
||
|
m_rcItemLabel.left,
|
||
|
m_nNewItemYPos - si.nPos,
|
||
|
m_rcItemLabel.right - m_rcItemLabel.left,
|
||
|
nLabelHeight,
|
||
|
hWnd,
|
||
|
(HMENU)IntToPtr(MAKE_LABEL_ID(m_cItems)),
|
||
|
hModule,
|
||
|
NULL);
|
||
|
if ( hwndNew )
|
||
|
{
|
||
|
HWND hwndEdit = hwndNew;
|
||
|
//
|
||
|
// Reset window height after word wrap has been done.
|
||
|
//
|
||
|
LONG nLineCount = (LONG) SendMessage(hwndNew, EM_GETLINECOUNT, 0, (LPARAM) 0);
|
||
|
nLabelHeight = nLineCount * m_nDefaultItemHeight;
|
||
|
SetWindowPos(hwndNew,
|
||
|
NULL,
|
||
|
0,
|
||
|
0,
|
||
|
m_rcItemLabel.right - m_rcItemLabel.left,
|
||
|
nLabelHeight,
|
||
|
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
|
||
|
|
||
|
//
|
||
|
// Save item data
|
||
|
//
|
||
|
lpUserData->lParam = lParam;
|
||
|
lpUserData->nLabelHeight = nLabelHeight;
|
||
|
lpUserData->itemIndex = m_cItems; //Raid #387542
|
||
|
|
||
|
SetLastError(0);
|
||
|
SetWindowLongPtr(hwndNew, GWLP_USERDATA, (LPARAM) lpUserData); //Raid #286697, 4/4/2001
|
||
|
if( 0 == GetLastError() )
|
||
|
{
|
||
|
// Set the font
|
||
|
SendMessage(hwndNew,
|
||
|
WM_SETFONT,
|
||
|
SendMessage(GetParent(hWnd), WM_GETFONT, 0, 0),
|
||
|
0);
|
||
|
|
||
|
// Set Z-order position just after the last checkbox. This keeps
|
||
|
// tab order correct.
|
||
|
if (m_cItems > 0)
|
||
|
{
|
||
|
hwndPrev = GetDlgItem(hWnd, MAKE_CTRL_ID(m_cItems - 1, m_cSubItems));
|
||
|
SetWindowPos(hwndNew,
|
||
|
hwndPrev,
|
||
|
0, 0, 0, 0,
|
||
|
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
|
||
|
}
|
||
|
|
||
|
// Create new checkboxes
|
||
|
DWORD dwCheckStyle = WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP | BS_NOTIFY | BS_FLAT | BS_AUTOCHECKBOX;
|
||
|
for (LONG j = 0; j < m_cSubItems; j++)
|
||
|
{
|
||
|
hwndPrev = hwndNew;
|
||
|
hwndNew = CreateWindowEx(WS_EX_NOPARENTNOTIFY,
|
||
|
TEXT("BUTTON"),
|
||
|
NULL,
|
||
|
dwCheckStyle,
|
||
|
m_nCheckPos[j],
|
||
|
m_nNewItemYPos - si.nPos,
|
||
|
m_cxCheckBox,
|
||
|
m_rcItemLabel.bottom - m_rcItemLabel.top,
|
||
|
hWnd,
|
||
|
(HMENU)IntToPtr(MAKE_CTRL_ID(m_cItems, j + 1)),
|
||
|
hModule,
|
||
|
NULL);
|
||
|
if (!hwndNew)
|
||
|
{
|
||
|
while (j >= 0)
|
||
|
{
|
||
|
DestroyWindow(GetDlgItem(hWnd, MAKE_CTRL_ID(m_cItems, j)));
|
||
|
j--;
|
||
|
}
|
||
|
|
||
|
DestroyWindow (hwndEdit);
|
||
|
delete lpUserData;
|
||
|
TraceLeaveValue(-1);
|
||
|
}
|
||
|
|
||
|
// Set Z-order position just after the last checkbox. This keeps
|
||
|
// tab order correct.
|
||
|
SetWindowPos(hwndNew,
|
||
|
hwndPrev,
|
||
|
0, 0, 0, 0,
|
||
|
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
|
||
|
|
||
|
//
|
||
|
// Default "enabled" to TRUE
|
||
|
//
|
||
|
SetWindowLongPtr(hwndNew, GWLP_USERDATA, (LPARAM) TRUE);
|
||
|
|
||
|
// Only want this style on the first checkbox
|
||
|
dwCheckStyle &= ~WS_GROUP;
|
||
|
}
|
||
|
|
||
|
// We now officially have a new item
|
||
|
m_cItems++;
|
||
|
|
||
|
// calculate Y pos for next item to be inserted
|
||
|
m_nNewItemYPos += nLabelHeight + m_nDefaultVerticalSpace;
|
||
|
|
||
|
//
|
||
|
// The last thing is to set the scroll range
|
||
|
//
|
||
|
GetClientRect(hWnd, &rc);
|
||
|
si.cbSize = sizeof(si);
|
||
|
si.fMask = SIF_PAGE | SIF_RANGE;
|
||
|
si.nMin = 0;
|
||
|
si.nMax = m_nNewItemYPos - 1;
|
||
|
si.nPage = rc.bottom;
|
||
|
|
||
|
SetScrollInfo(hWnd, SB_VERT, &si, FALSE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
delete lpUserData;
|
||
|
DestroyWindow(hwndNew);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
delete lpUserData;
|
||
|
}
|
||
|
|
||
|
TraceLeaveValue(m_cItems - 1); // return the index of the new item
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
CCheckList::SetState(HWND hWnd, WORD iItem, WORD iSubItem, LONG lState)
|
||
|
{
|
||
|
HWND hwndCtrl;
|
||
|
|
||
|
TraceEnter(TRACE_CHECKLIST, "CCheckList::SetState");
|
||
|
TraceAssert(hWnd != NULL);
|
||
|
TraceAssert(iItem < m_cItems);
|
||
|
TraceAssert(0 < iSubItem && iSubItem <= m_cSubItems);
|
||
|
|
||
|
if (iSubItem > 0)
|
||
|
{
|
||
|
hwndCtrl = GetDlgItem(hWnd, MAKE_CTRL_ID(iItem, iSubItem));
|
||
|
if (hwndCtrl != NULL)
|
||
|
{
|
||
|
SetWindowLongPtr(hwndCtrl, GWLP_USERDATA, (LPARAM) !(lState & CLST_DISABLED));
|
||
|
SendMessage(hwndCtrl, BM_SETCHECK, lState & CLST_CHECKED, 0);
|
||
|
EnableWindow(hwndCtrl, !(lState & CLST_DISABLED));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TraceLeaveVoid();
|
||
|
}
|
||
|
|
||
|
|
||
|
LONG
|
||
|
CCheckList::GetState(HWND hWnd, WORD iItem, WORD iSubItem)
|
||
|
{
|
||
|
LONG lState = 0;
|
||
|
|
||
|
TraceEnter(TRACE_CHECKLIST, "CCheckList::GetState");
|
||
|
TraceAssert(hWnd != NULL);
|
||
|
TraceAssert(iItem < m_cItems);
|
||
|
TraceAssert(0 < iSubItem && iSubItem <= m_cSubItems);
|
||
|
|
||
|
HWND hwndCtrl = GetDlgItem(hWnd, MAKE_CTRL_ID(iItem, iSubItem));
|
||
|
|
||
|
if (hwndCtrl != NULL)
|
||
|
{
|
||
|
lState = (LONG)SendMessage(hwndCtrl, BM_GETCHECK, 0, 0);
|
||
|
TraceAssert(!(lState & BST_INDETERMINATE));
|
||
|
|
||
|
if (!IsWindowEnabled(hwndCtrl))
|
||
|
lState |= CLST_DISABLED;
|
||
|
}
|
||
|
|
||
|
TraceLeaveValue(lState);
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
CCheckList::SetColumnWidth(HWND hWnd, LONG cxDialog, LONG cxColumn)
|
||
|
{
|
||
|
LONG j;
|
||
|
LPUSERDATA_STRUCT_LABEL pUserData;
|
||
|
LONG nLabelHeight;
|
||
|
|
||
|
TraceEnter(TRACE_CHECKLIST, "CCheckList::SetColumnWidth");
|
||
|
TraceAssert(hWnd != NULL);
|
||
|
TraceAssert(cxColumn > 10);
|
||
|
|
||
|
m_cxCheckColumn = cxColumn;
|
||
|
|
||
|
if (m_cSubItems > 0)
|
||
|
{
|
||
|
m_nCheckPos[m_cSubItems-1] = cxDialog // dlg width
|
||
|
- m_rcItemLabel.left // right margin
|
||
|
- (cxColumn + m_cxCheckBox)/2; // 1/2 col & 1/2 checkbox
|
||
|
|
||
|
for (j = m_cSubItems - 1; j > 0; j--)
|
||
|
m_nCheckPos[j-1] = m_nCheckPos[j] - cxColumn;
|
||
|
|
||
|
// (leftmost check pos) - (horz margin)
|
||
|
m_rcItemLabel.right = m_nCheckPos[0] - m_rcItemLabel.left;
|
||
|
}
|
||
|
else
|
||
|
m_rcItemLabel.right = cxDialog - m_rcItemLabel.left;
|
||
|
|
||
|
LONG nTop = m_rcItemLabel.top;
|
||
|
LONG nBottom = m_rcItemLabel.bottom;
|
||
|
|
||
|
for (LONG i = 0; i < m_cItems; i++)
|
||
|
{
|
||
|
pUserData = (LPUSERDATA_STRUCT_LABEL)
|
||
|
GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID((int)i)),
|
||
|
GWLP_USERDATA);
|
||
|
if (pUserData != NULL)
|
||
|
{
|
||
|
nLabelHeight = pUserData->nLabelHeight;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
nLabelHeight = nBottom - nTop;
|
||
|
}
|
||
|
|
||
|
MoveWindow(GetDlgItem(hWnd, MAKE_LABEL_ID(i)),
|
||
|
m_rcItemLabel.left,
|
||
|
nTop,
|
||
|
m_rcItemLabel.right - m_rcItemLabel.left,
|
||
|
nLabelHeight,
|
||
|
FALSE);
|
||
|
|
||
|
for (j = 0; j < m_cSubItems; j++)
|
||
|
{
|
||
|
MoveWindow(GetDlgItem(hWnd, MAKE_CTRL_ID(i, j + 1)),
|
||
|
m_nCheckPos[j],
|
||
|
nTop,
|
||
|
m_cxCheckBox,
|
||
|
nBottom - nTop,
|
||
|
FALSE);
|
||
|
}
|
||
|
|
||
|
nTop += nLabelHeight + m_nDefaultVerticalSpace;
|
||
|
nBottom += nLabelHeight + m_nDefaultVerticalSpace;
|
||
|
}
|
||
|
|
||
|
TraceLeaveVoid();
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
CCheckList::ResetContent(HWND hWnd)
|
||
|
{
|
||
|
LPUSERDATA_STRUCT_LABEL pUserData;
|
||
|
HWND hwndCurrentLabel;
|
||
|
|
||
|
for (LONG i = 0; i < m_cItems; i++)
|
||
|
{
|
||
|
hwndCurrentLabel = GetDlgItem(hWnd, MAKE_LABEL_ID((int)i));
|
||
|
pUserData = (LPUSERDATA_STRUCT_LABEL)
|
||
|
GetWindowLongPtr( hwndCurrentLabel,
|
||
|
GWLP_USERDATA);
|
||
|
if (pUserData != NULL)
|
||
|
{
|
||
|
delete(pUserData);
|
||
|
}
|
||
|
DestroyWindow(hwndCurrentLabel);
|
||
|
|
||
|
for (LONG j = 1; j <= m_cSubItems; j++)
|
||
|
{
|
||
|
DestroyWindow(GetDlgItem(hWnd, MAKE_CTRL_ID(i, j)));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Hide the scroll bar
|
||
|
SetScrollRange(hWnd, SB_VERT, 0, 0, FALSE);
|
||
|
m_cItems = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
LONG
|
||
|
CCheckList::GetVisibleCount(HWND hWnd)
|
||
|
{
|
||
|
LONG nCount = 0;
|
||
|
RECT rc;
|
||
|
LONG nTopIndex;
|
||
|
LONG nAmountShown = 0;
|
||
|
LONG nAmountObscured = 0;
|
||
|
LPUSERDATA_STRUCT_LABEL pUserData;
|
||
|
|
||
|
if (!GetClientRect(hWnd, &rc))
|
||
|
{
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
nTopIndex = GetTopIndex(hWnd, &nAmountObscured);
|
||
|
if (nTopIndex == -1)
|
||
|
{
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
while ((nTopIndex < m_cItems) && (nAmountShown < rc.bottom))
|
||
|
{
|
||
|
pUserData = (LPUSERDATA_STRUCT_LABEL)
|
||
|
GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID((int)nTopIndex)),
|
||
|
GWLP_USERDATA);
|
||
|
nAmountShown += (m_nDefaultVerticalSpace + pUserData->nLabelHeight - nAmountObscured);
|
||
|
nAmountObscured = 0; // nAmountObscured only matters for the first iteration where
|
||
|
// the real top index's amount shown is being calculated
|
||
|
nCount++;
|
||
|
nTopIndex++;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// since that last one may be obscured see if we need to adjust nCount
|
||
|
//
|
||
|
if (nAmountShown > rc.bottom)
|
||
|
{
|
||
|
nCount--;
|
||
|
}
|
||
|
|
||
|
return max(1, nCount);
|
||
|
}
|
||
|
|
||
|
LONG
|
||
|
CCheckList::GetTopIndex(HWND hWnd, LONG *pnAmountObscured)
|
||
|
{
|
||
|
LONG nIndex = 0;
|
||
|
LPUSERDATA_STRUCT_LABEL pUserData;
|
||
|
SCROLLINFO si;
|
||
|
si.cbSize = sizeof(si);
|
||
|
si.fMask = SIF_POS;
|
||
|
|
||
|
//
|
||
|
// initialize
|
||
|
//
|
||
|
if (pnAmountObscured != NULL)
|
||
|
{
|
||
|
*pnAmountObscured = 0;
|
||
|
}
|
||
|
|
||
|
if (GetScrollInfo(hWnd, SB_VERT, &si) && m_rcItemLabel.bottom > 0)
|
||
|
{
|
||
|
pUserData = (LPUSERDATA_STRUCT_LABEL)
|
||
|
GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID((int)nIndex)),
|
||
|
GWLP_USERDATA);
|
||
|
//
|
||
|
// if there are no items get out
|
||
|
//
|
||
|
if (pUserData == NULL)
|
||
|
{
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
while (si.nPos >= (m_nDefaultVerticalSpace + pUserData->nLabelHeight))
|
||
|
{
|
||
|
si.nPos -= (m_nDefaultVerticalSpace + pUserData->nLabelHeight);
|
||
|
nIndex++;
|
||
|
pUserData = (LPUSERDATA_STRUCT_LABEL)
|
||
|
GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID((int)nIndex)),
|
||
|
GWLP_USERDATA);
|
||
|
}
|
||
|
|
||
|
if (pnAmountObscured != NULL)
|
||
|
{
|
||
|
*pnAmountObscured = si.nPos;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nIndex;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
CCheckList::SetTopIndex(HWND hWnd, LONG nIndex)
|
||
|
{
|
||
|
int i;
|
||
|
int nPos = 0;
|
||
|
LPUSERDATA_STRUCT_LABEL pUserData;
|
||
|
|
||
|
for (i=0; i<nIndex; i++)
|
||
|
{
|
||
|
pUserData = (LPUSERDATA_STRUCT_LABEL)
|
||
|
GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID((int)i)),
|
||
|
GWLP_USERDATA);
|
||
|
nPos += (m_nDefaultVerticalSpace + pUserData->nLabelHeight);
|
||
|
}
|
||
|
|
||
|
m_cWheelDelta = 0;
|
||
|
MsgVScroll(hWnd, SB_THUMBPOSITION, nPos);
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
CCheckList::EnsureVisible(HWND hWnd, LONG nItemIndex)
|
||
|
{
|
||
|
LONG nAmountObscured = 0;
|
||
|
LONG nTopIndex;
|
||
|
RECT rc;
|
||
|
LPUSERDATA_STRUCT_LABEL pUserData;
|
||
|
|
||
|
nTopIndex = GetTopIndex(hWnd, &nAmountObscured);
|
||
|
if (nTopIndex == -1)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Note that the top item may only be partially visible,
|
||
|
// so we need to test for equality here. Raid #208449
|
||
|
if (nItemIndex < nTopIndex)
|
||
|
{
|
||
|
SetTopIndex(hWnd, nItemIndex);
|
||
|
}
|
||
|
else if (nItemIndex == nTopIndex)
|
||
|
{
|
||
|
if (nAmountObscured != 0)
|
||
|
{
|
||
|
SetTopIndex(hWnd, nItemIndex);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LONG nVisible = GetVisibleCount(hWnd);
|
||
|
|
||
|
if (nItemIndex >= nTopIndex + nVisible)
|
||
|
{
|
||
|
if (!GetClientRect(hWnd, &rc))
|
||
|
{
|
||
|
//
|
||
|
// This is just best effort
|
||
|
//
|
||
|
SetTopIndex(hWnd, nItemIndex - nVisible + 1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Calculate what the top index should be to allow
|
||
|
// nItemIndex to be fully visible
|
||
|
//
|
||
|
nTopIndex = nItemIndex + 1;
|
||
|
do
|
||
|
{
|
||
|
nTopIndex--;
|
||
|
pUserData = (LPUSERDATA_STRUCT_LABEL)
|
||
|
GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID((int)nTopIndex)),
|
||
|
GWLP_USERDATA);
|
||
|
if (pUserData != NULL)
|
||
|
{
|
||
|
rc.bottom -= (pUserData->nLabelHeight + m_nDefaultVerticalSpace);
|
||
|
if (rc.bottom < 0)
|
||
|
{
|
||
|
nTopIndex++;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Should not hit this, just added to make things safe
|
||
|
//
|
||
|
rc.bottom = 0;
|
||
|
nTopIndex = 0;
|
||
|
}
|
||
|
} while (rc.bottom > 0);
|
||
|
|
||
|
SetTopIndex(hWnd, nTopIndex);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
CCheckList::DrawCheckFocusRect(HWND hWnd, HWND hwndCheck, BOOL fDraw)
|
||
|
{
|
||
|
RECT rcCheck;
|
||
|
|
||
|
TraceEnter(TRACE_CHECKLIST, "CCheckList::DrawCheckFocusRect");
|
||
|
TraceAssert(hWnd != NULL);
|
||
|
TraceAssert(hwndCheck != NULL);
|
||
|
|
||
|
GetWindowRect(hwndCheck, &rcCheck);
|
||
|
MapWindowPoints(NULL, hWnd, (LPPOINT)&rcCheck, 2);
|
||
|
InflateRect(&rcCheck, 2, 2); // draw *outside* the checkbox
|
||
|
|
||
|
HDC hdc = GetDC(hWnd);
|
||
|
if (hdc)
|
||
|
{
|
||
|
// Always erase before drawing, since we may already be
|
||
|
// partially visible and drawing is an XOR operation.
|
||
|
// (Don't want to leave any turds on the screen.)
|
||
|
|
||
|
FrameRect(hdc, &rcCheck, GetSysColorBrush(BK_COLOR));
|
||
|
|
||
|
if (fDraw)
|
||
|
{
|
||
|
SetTextColor(hdc, GetSysColor(TEXT_COLOR));
|
||
|
SetBkColor(hdc, GetSysColor(BK_COLOR));
|
||
|
DrawFocusRect(hdc, &rcCheck);
|
||
|
}
|
||
|
|
||
|
ReleaseDC(hWnd, hdc);
|
||
|
}
|
||
|
|
||
|
TraceLeaveVoid();
|
||
|
}
|
||
|
|
||
|
LRESULT
|
||
|
CALLBACK
|
||
|
CCheckList::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
LRESULT lResult = 0;
|
||
|
LPUSERDATA_STRUCT_LABEL pUserData = NULL;
|
||
|
CCheckList *pThis = (CCheckList*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
|
||
|
|
||
|
TraceEnter(TRACE_CHECKLIST, "CCheckList::WindowProc");
|
||
|
TraceAssert(hWnd != NULL);
|
||
|
|
||
|
switch (uMsg)
|
||
|
{
|
||
|
case WM_NCCREATE:
|
||
|
pThis = new CCheckList(hWnd, (LPCREATESTRUCT)lParam);
|
||
|
if (pThis != NULL)
|
||
|
{
|
||
|
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pThis);
|
||
|
lResult = TRUE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WM_DESTROY:
|
||
|
pThis->ResetContent(hWnd);
|
||
|
break;
|
||
|
|
||
|
case WM_NCDESTROY:
|
||
|
delete pThis;
|
||
|
break;
|
||
|
|
||
|
case WM_COMMAND:
|
||
|
TraceAssert(pThis != NULL);
|
||
|
lResult = pThis->MsgCommand(hWnd,
|
||
|
GET_WM_COMMAND_ID(wParam, lParam),
|
||
|
GET_WM_COMMAND_CMD(wParam, lParam),
|
||
|
GET_WM_COMMAND_HWND(wParam, lParam));
|
||
|
break;
|
||
|
|
||
|
case WM_CTLCOLORSTATIC:
|
||
|
TraceAssert(pThis != NULL);
|
||
|
SetBkMode((HDC)wParam, TRANSPARENT);
|
||
|
SetTextColor((HDC)wParam, GetSysColor(TEXT_COLOR));
|
||
|
SetBkColor((HDC)wParam, GetSysColor(BK_COLOR));
|
||
|
lResult = (LRESULT)GetSysColorBrush(BK_COLOR);
|
||
|
break;
|
||
|
|
||
|
case WM_PAINT:
|
||
|
TraceAssert(pThis != NULL);
|
||
|
pThis->MsgPaint(hWnd, (HDC)wParam);
|
||
|
break;
|
||
|
|
||
|
case WM_VSCROLL:
|
||
|
TraceAssert(pThis != NULL);
|
||
|
pThis->MsgVScroll(hWnd,
|
||
|
(int)(short)GET_WM_VSCROLL_CODE(wParam, lParam),
|
||
|
(int)(short)GET_WM_VSCROLL_POS(wParam, lParam));
|
||
|
break;
|
||
|
|
||
|
case WM_MOUSEWHEEL:
|
||
|
TraceAssert(pThis != NULL);
|
||
|
pThis->MsgMouseWheel(hWnd,
|
||
|
LOWORD(wParam),
|
||
|
(int)(short)HIWORD(wParam));
|
||
|
break;
|
||
|
|
||
|
case WM_LBUTTONDOWN:
|
||
|
TraceAssert(pThis != NULL);
|
||
|
pThis->MsgButtonDown(hWnd,
|
||
|
wParam,
|
||
|
(int)(short)LOWORD(lParam),
|
||
|
(int)(short)HIWORD(lParam));
|
||
|
break;
|
||
|
|
||
|
case WM_ENABLE:
|
||
|
TraceAssert(pThis != NULL);
|
||
|
pThis->MsgEnable(hWnd, (BOOL)wParam);
|
||
|
break;
|
||
|
|
||
|
case WM_SETFONT:
|
||
|
TraceAssert(pThis != NULL);
|
||
|
{
|
||
|
for (LONG i = 0; i < pThis->m_cItems; i++)
|
||
|
SendDlgItemMessage(hWnd,
|
||
|
MAKE_LABEL_ID(i),
|
||
|
WM_SETFONT,
|
||
|
wParam,
|
||
|
lParam);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WM_SIZE:
|
||
|
TraceAssert(pThis != NULL);
|
||
|
pThis->MsgSize(hWnd, (DWORD)wParam, LOWORD(lParam), HIWORD(lParam));
|
||
|
break;
|
||
|
|
||
|
case CLM_ADDITEM:
|
||
|
TraceAssert(pThis != NULL);
|
||
|
lResult = pThis->AddItem(hWnd, (LPCTSTR)wParam, lParam);
|
||
|
break;
|
||
|
|
||
|
case CLM_GETITEMCOUNT:
|
||
|
TraceAssert(pThis != NULL);
|
||
|
lResult = pThis->m_cItems;
|
||
|
break;
|
||
|
|
||
|
case CLM_SETSTATE:
|
||
|
TraceAssert(pThis != NULL);
|
||
|
pThis->SetState(hWnd, LOWORD(wParam), HIWORD(wParam), (LONG)lParam);
|
||
|
break;
|
||
|
|
||
|
case CLM_GETSTATE:
|
||
|
TraceAssert(pThis != NULL);
|
||
|
lResult = pThis->GetState(hWnd, LOWORD(wParam), HIWORD(wParam));
|
||
|
break;
|
||
|
|
||
|
case CLM_SETCOLUMNWIDTH:
|
||
|
TraceAssert(pThis != NULL);
|
||
|
{
|
||
|
RECT rc;
|
||
|
LONG cxDialog;
|
||
|
|
||
|
GetClientRect(hWnd, &rc);
|
||
|
cxDialog = rc.right;
|
||
|
|
||
|
rc.right = (LONG)lParam;
|
||
|
MapDialogRect(GetParent(hWnd), &rc);
|
||
|
|
||
|
pThis->SetColumnWidth(hWnd, cxDialog, rc.right);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case CLM_SETITEMDATA:
|
||
|
TraceAssert(GET_ITEM(wParam) < (ULONG)pThis->m_cItems);
|
||
|
pUserData = (LPUSERDATA_STRUCT_LABEL)
|
||
|
GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID((int)wParam)),
|
||
|
GWLP_USERDATA);
|
||
|
if (pUserData != NULL)
|
||
|
pUserData->lParam = lParam;
|
||
|
break;
|
||
|
|
||
|
case CLM_GETITEMDATA:
|
||
|
TraceAssert(GET_ITEM(wParam) < (ULONG)pThis->m_cItems);
|
||
|
pUserData = (LPUSERDATA_STRUCT_LABEL)
|
||
|
GetWindowLongPtr( GetDlgItem(hWnd, MAKE_LABEL_ID((int)wParam)),
|
||
|
GWLP_USERDATA);
|
||
|
if (pUserData != NULL)
|
||
|
lResult = pUserData->lParam;
|
||
|
break;
|
||
|
|
||
|
case CLM_RESETCONTENT:
|
||
|
TraceAssert(pThis != NULL);
|
||
|
pThis->ResetContent(hWnd);
|
||
|
break;
|
||
|
|
||
|
case CLM_GETVISIBLECOUNT:
|
||
|
TraceAssert(pThis != NULL);
|
||
|
lResult = pThis->GetVisibleCount(hWnd);
|
||
|
break;
|
||
|
|
||
|
case CLM_GETTOPINDEX:
|
||
|
TraceAssert(pThis != NULL);
|
||
|
lResult = pThis->GetTopIndex(hWnd);
|
||
|
break;
|
||
|
|
||
|
case CLM_SETTOPINDEX:
|
||
|
TraceAssert(pThis != NULL);
|
||
|
pThis->SetTopIndex(hWnd, (LONG)wParam);
|
||
|
break;
|
||
|
|
||
|
case CLM_ENSUREVISIBLE:
|
||
|
TraceAssert(pThis != NULL);
|
||
|
pThis->EnsureVisible(hWnd, (LONG)wParam);
|
||
|
break;
|
||
|
|
||
|
//
|
||
|
// Always refer to the chklist window for help. Don't pass
|
||
|
// one of the child window handles here.
|
||
|
//
|
||
|
case WM_HELP:
|
||
|
((LPHELPINFO)lParam)->hItemHandle = hWnd;
|
||
|
lResult = SendMessage(GetParent(hWnd), uMsg, wParam, lParam);
|
||
|
break;
|
||
|
case WM_CONTEXTMENU:
|
||
|
lResult = SendMessage(GetParent(hWnd), uMsg, (WPARAM)hWnd, lParam);
|
||
|
break;
|
||
|
|
||
|
case WM_SETCURSOR:
|
||
|
if (LOWORD(lParam) == HTCLIENT)
|
||
|
{
|
||
|
SetCursor(LoadCursor(NULL, IDC_ARROW));
|
||
|
lResult = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
// Fall Through
|
||
|
default:
|
||
|
lResult = DefWindowProc(hWnd, uMsg, wParam, lParam);
|
||
|
}
|
||
|
|
||
|
TraceLeaveValue(lResult);
|
||
|
}
|