561 lines
16 KiB
C++
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;
|
|
}
|