// 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; }