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

561 lines
16 KiB
C++

// Copyright (C) Microsoft Corporation 1996-1997, All Rights reserved.
#include "header.h"
#include "cdlg.h"
#include "strtable.h"
#include "cpaldc.h"
// CLockOut for disabling the outer level windows.
#include "lockout.h"
#ifndef IDBMP_CHECK
#include "resource.h"
#endif
static BOOL WINAPI EnumFontProc(HWND hwnd, LPARAM lval);
static BOOL WINAPI EnumBidiSettings(HWND hwnd, LPARAM lval);
CDlg::CDlg(HWND hwndParent, UINT idTemplate)
{
ZERO_INIT_CLASS(CDlg);
m_hwndParent = hwndParent;
if(g_bWinNT5)
m_lpDialogTemplate = (char *)MAKEINTRESOURCEW(idTemplate);
else
m_lpDialogTemplate = MAKEINTRESOURCE(idTemplate);
m_fCenterWindow = TRUE;
m_phhCtrl = NULL;
m_fUnicode = g_bWinNT5;
}
CDlg::CDlg(CHtmlHelpControl* phhCtrl, UINT idTemplate)
{
ZERO_INIT_CLASS(CDlg);
ASSERT(phhCtrl);
m_hwndParent = phhCtrl->m_hwnd;
if(g_bWinNT5)
m_lpDialogTemplate = (char *)MAKEINTRESOURCEW(idTemplate);
else
m_lpDialogTemplate = MAKEINTRESOURCE(idTemplate);
m_fCenterWindow = TRUE;
m_phhCtrl = phhCtrl;
m_fUnicode = g_bWinNT5;
}
int CDlg::DoModal(void)
{
if (m_phhCtrl)
m_phhCtrl->ModalDialog(TRUE);
else
m_LockOut.LockOut(m_hwndParent) ;
int result = -1;
if (m_fUnicode || g_bWinNT5)
{
result = (int)::DialogBoxParamW(_Module.GetResourceInstance(), (LPCWSTR)m_lpDialogTemplate,
m_hwndParent, (DLGPROC) CDlgProc, (LPARAM) this);
// Docs say this returns -1 for failure, but returns 0 on
// Win95 like other unimplemented APIs.
if (0 == result)
{
if (ERROR_CALL_NOT_IMPLEMENTED == GetLastError())
{
m_fUnicode = FALSE;
goto _Ansi;
}
}
}
else
{
_Ansi: result = (int)::DialogBoxParamA(_Module.GetResourceInstance(), m_lpDialogTemplate,
m_hwndParent, (DLGPROC) CDlgProc, (LPARAM) this);
}
if (m_phhCtrl)
m_phhCtrl->ModalDialog(FALSE);
return result;
}
CDlg::~CDlg()
{
if (m_fModeLess && IsValidWindow(m_hWnd))
DestroyWindow(m_hWnd);
if (m_pCheckBox)
delete m_pCheckBox;
}
void STDCALL CenterWindow(HWND hwndParent, HWND hwnd)
{
RECT rcParent, rc;
//BUGBUG: This is broken in the multiple monitor case.
if (!hwndParent)
hwndParent = GetDesktopWindow();
GetWindowRect(hwndParent, &rcParent);
GetWindowRect(hwnd, &rc);
int cx = RECT_WIDTH(rc);
int cy = RECT_HEIGHT(rc);
int left = rcParent.left + (RECT_WIDTH(rcParent) - cx) / 2;
int top = rcParent.top + (RECT_HEIGHT(rcParent) - cy) / 2;
// Make certain we don't cover the tray
// Also make sure that the dialog box is completely visible.
// If its not visible, then let the default happen.
SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0);
if (left < rc.left)
left = rc.left;
if (top < rc.top)
top = rc.top;
// BUG 2426: Make sure that the window is visible.
if (left+cx > rc.right)
left = rc.right - cx ;
if (top+cy > rc.bottom)
top = rc.bottom - cy ;
// Make sure that the dialog still fits.
ASSERT(left >= rc.left && top >= rc.top);
// Make sure that the window is completely visible before doing the move:
MoveWindow(hwnd, left, top, cx, cy, TRUE);
}
BOOL CALLBACK CDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
CDlg* pThis = (CDlg*) GetWindowLongPtr(hdlg, GWLP_USERDATA);
switch (msg) {
case WM_INITDIALOG:
// Save this pointer in the window data area
pThis = (CDlg*) lParam;
SetWindowLongPtr(hdlg, GWLP_USERDATA, lParam);
pThis->m_hWnd = hdlg;
pThis->m_fInitializing = TRUE; // reset when IDOK processed
if (pThis->m_fCenterWindow)
CenterWindow(pThis->m_hwndParent, pThis->m_hWnd);
if (pThis->m_pBeginOrEnd)
pThis->m_pBeginOrEnd(pThis);
else
pThis->OnBeginOrEnd();
// set the correct font
//
if(g_bWinNT5)
EnumChildWindows(hdlg, (WNDENUMPROC) EnumFontProc, 0);
if (g_fBiDi) {
// If BiDi, make adjustments to list and combo boxes
EnumChildWindows(hdlg, (WNDENUMPROC) EnumBidiSettings, 0);
}
if (pThis->m_aHelpIds)
SetWindowLong(hdlg, GWL_EXSTYLE,
GetWindowLong(hdlg, GWL_EXSTYLE) | WS_EX_CONTEXTHELP);
// If we're threaded, we may be behind our caller
SetWindowPos(hdlg, HWND_TOP, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE);
//BUG 2035: Return TRUE to tell windows to set the keyboard focus.
// m_fFocusChanged is FALSE if the derived class hasn't changed it.
return !pThis->m_fFocusChanged;
case WM_COMMAND:
{
pThis = (CDlg*) GetWindowLongPtr(hdlg, GWLP_USERDATA);
if (!pThis || pThis->m_fShuttingDown)
return FALSE; // pThis == NULL if a spin control is being initialized
switch (HIWORD(wParam)) {
case BN_CLICKED:
pThis->OnButton(LOWORD(wParam));
break;
case LBN_SELCHANGE: // same value as CBN_SELCHANGE
pThis->OnSelChange(LOWORD(wParam));
break;
case LBN_DBLCLK: // same value as CBN_DBLCLK
pThis->OnDoubleClick(LOWORD(wParam));
break;
case EN_CHANGE:
pThis->OnEditChange(LOWORD(wParam));
break;
}
// If m_pmsglist is set, OnCommand will call OnMsg
if (!pThis->OnCommand(wParam, lParam))
return FALSE;
BOOL fResult;
switch (LOWORD(wParam)) {
case IDOK:
pThis->m_fInitializing = FALSE;
fResult = -1;
if (pThis->m_pBeginOrEnd)
fResult = pThis->m_pBeginOrEnd(pThis);
else
fResult = pThis->OnBeginOrEnd();
if (!fResult)
break;
if (pThis->m_fModeLess) {
pThis->m_fShuttingDown = TRUE;
PostMessage(hdlg, WM_CLOSE, 0, 0);
}
else
pThis->m_LockOut.Unlock();
EndDialog(hdlg, TRUE);
break;
case IDCANCEL:
if (pThis->m_fModeLess) {
pThis->m_fShuttingDown = TRUE;
PostMessage(hdlg, WM_CLOSE, 0, 0);
}
else
pThis->m_LockOut.Unlock();
EndDialog(hdlg, FALSE);
break;
case IDNO:
if (pThis->m_fModeLess) {
pThis->m_fShuttingDown = TRUE;
PostMessage(hdlg, WM_CLOSE, 0, 0);
}
else
pThis->m_LockOut.Unlock();
EndDialog(hdlg, IDNO);
break;
case IDRETRY:
if (pThis->m_fModeLess) {
pThis->m_fShuttingDown = TRUE;
PostMessage(hdlg, WM_CLOSE, 0, 0);
}
else
pThis->m_LockOut.Unlock();
EndDialog(hdlg, IDRETRY);
break;
default:
break;
}
}
break;
case WM_HELP:
pThis->OnHelp((HWND) ((LPHELPINFO) lParam)->hItemHandle);
break;
case WM_CONTEXTMENU:
pThis->OnContextMenu((HWND) wParam);
break;
case WM_DRAWITEM:
if (!pThis)
return FALSE;
if (pThis->m_pCheckBox &&
GetDlgItem(hdlg, (int)wParam) == pThis->m_pCheckBox->m_hWnd) {
ASSERT(IsValidWindow(pThis->m_pCheckBox->m_hWnd));
pThis->m_pCheckBox->DrawItem((DRAWITEMSTRUCT*) lParam);
return TRUE;
}
else
return (int)pThis->OnDlgMsg(msg, wParam, lParam);
case WM_VKEYTOITEM:
if (pThis && pThis->m_pCheckBox && (HWND) lParam == pThis->m_pCheckBox->m_hWnd) {
if (LOWORD(wParam) == VK_SPACE) {
int cursel = (int)pThis->m_pCheckBox->GetCurSel();
if (cursel != LB_ERR)
pThis->m_pCheckBox->ToggleItem(cursel);
}
return -1; // always perform default action
}
else
return (int)pThis->OnDlgMsg(msg, wParam, lParam);
default:
if (pThis)
return (int)pThis->OnDlgMsg(msg, wParam, lParam);
else
return FALSE;
}
return FALSE;
}
/***************************************************************************
FUNCTION: CDlg::OnMsg
PURPOSE: Parse an array of messages and ids. If the message is
intended for an id, call the associated function.
PARAMETERS:
wParam
RETURNS: TRUE if no message was processed (i.e., continue processing).
FALSE if message processed
COMMENTS:
MODIFICATION DATES:
16-Apr-1997 [ralphw]
***************************************************************************/
BOOL CDlg::OnMsg(WPARAM wParam)
{
if (!m_pmsglist)
return TRUE;
UINT msg = HIWORD(wParam);
UINT id = LOWORD(wParam);
const CDLG_MESSAGE_LIST* pmsglist = m_pmsglist;
for (;pmsglist->idControl; pmsglist++) {
if (msg == pmsglist->idMessage && id == pmsglist->idControl) {
(this->*pmsglist->pfunc)();
return FALSE;
}
}
return TRUE; // continue processing
}
HWND CDlg::DoModeless(void)
{
HWND hwnd = NULL;
m_fModeLess = TRUE;
if (m_fUnicode)
{
hwnd = ::CreateDialogParamW(_Module.GetResourceInstance(), (LPCWSTR)m_lpDialogTemplate,
m_hwndParent, (DLGPROC) CDlgProc, (LPARAM) this);
if (NULL == hwnd)
{
if (ERROR_CALL_NOT_IMPLEMENTED == GetLastError())
{
m_fUnicode = FALSE;
goto _Ansi;
}
}
}
else
{
_Ansi: hwnd = ::CreateDialogParamA(_Module.GetResourceInstance(), m_lpDialogTemplate, m_hwndParent,
(DLGPROC) CDlgProc, (LPARAM) this);
}
ASSERT(IsValidWindow(m_hWnd) && hwnd == m_hWnd);
::ShowWindow(m_hWnd, SW_SHOW);
return m_hWnd;
}
LRESULT CDlg::OnContextMenu(HWND hwnd)
{
if (m_aHelpIds)
WinHelp(hwnd, m_pszHelpFile,
HELP_CONTEXTMENU, (DWORD_PTR) (LPVOID) m_aHelpIds);
return 0;
}
LRESULT CDlg::OnHelp(HWND hwnd)
{
if (m_aHelpIds)
WinHelp(hwnd, m_pszHelpFile,
HELP_WM_HELP, (DWORD_PTR) (LPVOID) m_aHelpIds);
return 0;
}
static BOOL WINAPI EnumFontProc(HWND hwnd, LPARAM lval)
{
SendMessage(hwnd, WM_SETFONT, (WPARAM) _Resource.GetUIFont(), FALSE);
return TRUE;
}
static BOOL WINAPI EnumBidiSettings(HWND hwnd, LPARAM lval)
{
char szClass[MAX_PATH];
VERIFY(GetClassName(hwnd, szClass, sizeof(szClass)));
// In BiDi, flip the scroll bars to the left side
if (IsSamePrefix(szClass, "LISTBOX", -2) ||
IsSamePrefix(szClass, "COMBOBOX", -2)) {
::SetWindowLong(hwnd, GWL_EXSTYLE,
WS_EX_LEFTSCROLLBAR | ::GetWindowLong(hwnd, GWL_EXSTYLE));
}
return TRUE;
}
void CDlgListBox::RemoveListItem()
{
int cursel;
if ((cursel = (int)GetCurSel()) != LB_ERR) {
// Delete current selection, and select the item below it
DeleteString(cursel);
if (cursel < GetCount())
SetCurSel(cursel);
else if (cursel > 0)
SetCurSel(--cursel);
else if (GetCount())
SetCurSel(0);
}
}
void CDlg::MakeCheckedList(int idLB)
{
if (!m_pCheckBox)
m_pCheckBox = new CDlgCheckListBox;
m_pCheckBox->Initialize(*this, idLB);
}
CDlgCheckListBox::CDlgCheckListBox()
{
m_xMargin = GetSystemMetrics(SM_CXBORDER);
m_yMargin = GetSystemMetrics(SM_CYBORDER);
m_cxDlgFrame = GetSystemMetrics(SM_CXDLGFRAME);
m_hbmpCheck = LoadBitmap(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDBMP_CHECK));
ASSERT(m_hbmpCheck);
BITMAP bmp;
GetObject(m_hbmpCheck, sizeof(BITMAP), &bmp);
m_cxCheck = bmp.bmWidth / 3;
m_cyCheck = bmp.bmHeight;
m_iLastSel = LB_ERR;
}
CDlgCheckListBox::~CDlgCheckListBox()
{
DeleteObject(m_hbmpCheck);
}
BOOL CDlgCheckListBox::IsItemChecked (int nIndex) const
{
return (BOOL) GetItemData(nIndex);
}
void CDlgCheckListBox::CheckItem(int nIndex, BOOL fChecked /*= TRUE*/)
{
SetItemData(nIndex, fChecked);
InvalidateItem(nIndex);
}
void CDlgCheckListBox::ToggleItem (int nIndex)
{
CheckItem(nIndex, IsItemChecked(nIndex) ? FALSE : TRUE);
}
int CDlgCheckListBox::ItemHeight(void)
{
HDC hdc = GetDC(m_hWnd);
SIZE size;
VERIFY(GetTextExtentPoint(hdc, "M", 1, &size));
ReleaseDC(m_hWnd, hdc);
return size.cy; // + GetSystemMetrics (SM_CYBORDER);
}
void CDlgCheckListBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
ASSERT (lpDrawItemStruct != NULL);
// Ignore if not redrawing 1
if (lpDrawItemStruct->itemID != LB_ERR &&
(lpDrawItemStruct->itemAction & (ODA_SELECT | ODA_DRAWENTIRE))) {
CStr cszText;
int cbText = (int)GetTextLength(lpDrawItemStruct->itemID);
cszText.psz = (PSTR) lcMalloc(cbText + 1);
GetText(cszText.psz, cbText + 1, lpDrawItemStruct->itemID);
SetTextColor(lpDrawItemStruct->hDC,
GetSysColor((lpDrawItemStruct->itemState & ODS_SELECTED) ?
COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT));
SetBkColor(lpDrawItemStruct->hDC,
GetSysColor((lpDrawItemStruct->itemState & ODS_SELECTED) ?
COLOR_HIGHLIGHT : COLOR_WINDOW));
RECT rcItem;
RECT rcCheck;
GetItemRect(&rcItem, lpDrawItemStruct->itemID);
GetCheckRect(lpDrawItemStruct->itemID, &rcCheck);
int yTextOffset = max(0, (RECT_HEIGHT(rcItem) - ItemHeight()) / 2);
int xTextOffset = 2 * m_cxDlgFrame + RECT_WIDTH(rcCheck);
ExtTextOut(lpDrawItemStruct->hDC,
rcItem.left + xTextOffset, rcItem.top + yTextOffset,
ETO_OPAQUE, &rcItem, cszText, cbText, NULL);
DrawCheck(lpDrawItemStruct->hDC, &rcCheck, IsItemChecked(lpDrawItemStruct->itemID));
}
}
void CDlgCheckListBox::InvalidateItem(int nIndex, BOOL fRedraw /*= FALSE*/)
{
RECT rc;
if (GetItemRect(&rc, nIndex) != LB_ERR)
InvalidateRect(m_hWnd, &rc, fRedraw);
}
void CDlgCheckListBox::DrawCheck(HDC hdc, RECT* prc, BOOL fChecked)
{
CPalDC dcBmp(m_hbmpCheck);
BitBlt(hdc, prc->left, prc->top,
m_cxCheck, m_cyCheck, dcBmp,
m_cyCheck * (fChecked ? 1 : 0), 0, SRCCOPY);
}
const int CHECK_MARGIN = 2;
int CDlgCheckListBox::GetCheckRect(int nIndex, RECT* prc)
{
if (GetItemRect(prc, nIndex) == LB_ERR)
return LB_ERR;
prc->left += CHECK_MARGIN;
prc->right = prc->left + m_cxCheck;
if (RECT_HEIGHT(prc) > m_cyCheck) {
int diff = (RECT_HEIGHT(prc) - m_cyCheck) / 2;
prc->top += diff;
}
return 0;
}
void CDlgCheckListBox::OnSelChange(void)
{
int pos = (int)GetCurSel();
if (pos != LB_ERR) {
POINT pt;
GetCursorPos(&pt);
ScreenToClient(*this, &pt);
RECT rc;
GetCheckRect(pos, &rc);
if (PtInRect(&rc, pt))
ToggleItem(pos);
else if (pos == m_iLastSel)
ToggleItem(pos);
}
m_iLastSel = pos;
}