From 345930435561acd026c9356f01065e7ee0e92101 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20P=C3=B6sel?= Date: Tue, 29 Oct 2013 22:15:21 +0000 Subject: Adopted SmartAutoReplier plugin First compilable version. git-svn-id: http://svn.miranda-ng.org/main/trunk@6693 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/SmartAutoReplier/wtl/atlframe.h | 3688 +++++++++++++++++++++++++++++++ 1 file changed, 3688 insertions(+) create mode 100644 plugins/SmartAutoReplier/wtl/atlframe.h (limited to 'plugins/SmartAutoReplier/wtl/atlframe.h') diff --git a/plugins/SmartAutoReplier/wtl/atlframe.h b/plugins/SmartAutoReplier/wtl/atlframe.h new file mode 100644 index 0000000000..252e50e902 --- /dev/null +++ b/plugins/SmartAutoReplier/wtl/atlframe.h @@ -0,0 +1,3688 @@ +// Windows Template Library - WTL version 8.1 +// Copyright (C) Microsoft Corporation. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php) +// which can be found in the file CPL.TXT at the root of this distribution. +// By using this software in any fashion, you are agreeing to be bound by +// the terms of this license. You must not remove this notice, or +// any other, from this software. + +#ifndef __ATLFRAME_H__ +#define __ATLFRAME_H__ + +#pragma once + +#ifndef __ATLAPP_H__ + #error atlframe.h requires atlapp.h to be included first +#endif + +#ifndef __ATLWIN_H__ + #error atlframe.h requires atlwin.h to be included first +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CFrameWindowImpl +// CMDIWindow +// CMDIFrameWindowImpl +// CMDIChildWindowImpl +// COwnerDraw +// CUpdateUIBase +// CUpdateUI +// CDynamicUpdateUI +// CAutoUpdateUI +// CDialogResize +// CDoubleBufferImpl +// CDoubleBufferWindowImpl +// +// Global functions: +// AtlCreateSimpleToolBar() + + +namespace WTL +{ + +/////////////////////////////////////////////////////////////////////////////// +// CFrameWndClassInfo - Manages frame window Windows class information + +class CFrameWndClassInfo +{ +public: +#ifndef _WIN32_WCE + enum { cchAutoName = 5 + sizeof(void*) * 2 }; // sizeof(void*) * 2 is the number of digits %p outputs + WNDCLASSEX m_wc; +#else // CE specific + enum { cchAutoName = MAX_PATH }; // MAX_PATH because this can be set in the wizard generated CMainFrame::ActivatePreviousInstance to a user defined string. + WNDCLASS m_wc; +#endif // !_WIN32_WCE + LPCTSTR m_lpszOrigName; + WNDPROC pWndProc; + LPCTSTR m_lpszCursorID; + BOOL m_bSystemCursor; + ATOM m_atom; + TCHAR m_szAutoName[cchAutoName]; + UINT m_uCommonResourceID; + +#ifndef _WIN32_WCE + ATOM Register(WNDPROC* pProc) + { + if (m_atom == 0) + { + CWindowCreateCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CFrameWndClassInfo::Register.\n")); + ATLASSERT(FALSE); + return 0; + } + + if(m_atom == 0) + { + HINSTANCE hInst = ModuleHelper::GetModuleInstance(); + + if (m_lpszOrigName != NULL) + { + ATLASSERT(pProc != NULL); + LPCTSTR lpsz = m_wc.lpszClassName; + WNDPROC proc = m_wc.lpfnWndProc; + + WNDCLASSEX wc = { 0 }; + wc.cbSize = sizeof(WNDCLASSEX); + // try process local class first + if(!::GetClassInfoEx(ModuleHelper::GetModuleInstance(), m_lpszOrigName, &wc)) + { + // try global class + if(!::GetClassInfoEx(NULL, m_lpszOrigName, &wc)) + { + lock.Unlock(); + return 0; + } + } + m_wc = wc; + pWndProc = m_wc.lpfnWndProc; + m_wc.lpszClassName = lpsz; + m_wc.lpfnWndProc = proc; + } + else + { + m_wc.hCursor = ::LoadCursor(m_bSystemCursor ? NULL : hInst, m_lpszCursorID); + } + + m_wc.hInstance = hInst; + m_wc.style &= ~CS_GLOBALCLASS; // we don't register global classes + if (m_wc.lpszClassName == NULL) + { +#if (_WIN32_WINNT >= 0x0500) || defined(_WIN64) + SecureHelper::wsprintf_x(m_szAutoName, cchAutoName, _T("ATL:%p"), &m_wc); +#else // !((_WIN32_WINNT >= 0x0500) || defined(_WIN64)) + SecureHelper::wsprintf_x(m_szAutoName, cchAutoName, _T("ATL:%8.8X"), (DWORD_PTR)&m_wc); +#endif // !((_WIN32_WINNT >= 0x0500) || defined(_WIN64)) + m_wc.lpszClassName = m_szAutoName; + } + + WNDCLASSEX wcTemp = m_wc; + m_atom = (ATOM)::GetClassInfoEx(m_wc.hInstance, m_wc.lpszClassName, &wcTemp); + if (m_atom == 0) + { + if(m_uCommonResourceID != 0) // use it if not zero + { + m_wc.hIcon = (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR); + m_wc.hIconSm = (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); + } + m_atom = ::RegisterClassEx(&m_wc); + } + } + + lock.Unlock(); + } + + if (m_lpszOrigName != NULL) + { + ATLASSERT(pProc != NULL); + ATLASSERT(pWndProc != NULL); + *pProc = pWndProc; + } + + return m_atom; + } +#else // CE specific + ATOM Register(WNDPROC* pProc) + { + if (m_atom == 0) + { + CWindowCreateCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CFrameWndClassInfo::Register.\n")); + ATLASSERT(FALSE); + return 0; + } + + if(m_atom == 0) + { + HINSTANCE hInst = ModuleHelper::GetModuleInstance(); + + if (m_lpszOrigName != NULL) + { + ATLASSERT(pProc != NULL); + LPCTSTR lpsz = m_wc.lpszClassName; + WNDPROC proc = m_wc.lpfnWndProc; + + WNDCLASS wc = { 0 }; + // try process local class first + if(!::GetClassInfo(ModuleHelper::GetModuleInstance(), m_lpszOrigName, &wc)) + { + // try global class + if(!::GetClassInfo(NULL, m_lpszOrigName, &wc)) + { + lock.Unlock(); + return 0; + } + } + m_wc = wc; + pWndProc = m_wc.lpfnWndProc; + m_wc.lpszClassName = lpsz; + m_wc.lpfnWndProc = proc; + } + else + { +#if defined(GWES_CURSOR) || defined(GWES_MCURSOR) + m_wc.hCursor = ::LoadCursor(m_bSystemCursor ? NULL : hInst, m_lpszCursorID); +#else // !(defined(GWES_CURSOR) || defined(GWES_MCURSOR)) + m_wc.hCursor = NULL; +#endif // !(defined(GWES_CURSOR) || defined(GWES_MCURSOR)) + } + + m_wc.hInstance = hInst; + m_wc.style &= ~CS_GLOBALCLASS; // we don't register global classes + if (m_wc.lpszClassName == NULL) + { + wsprintf(m_szAutoName, _T("ATL:%8.8X"), (DWORD_PTR)&m_wc); + m_wc.lpszClassName = m_szAutoName; + } + + WNDCLASS wcTemp = m_wc; + m_atom = (ATOM)::GetClassInfo(m_wc.hInstance, m_wc.lpszClassName, &wcTemp); + if (m_atom == 0) + { + if(m_uCommonResourceID != 0) // use it if not zero + m_wc.hIcon = (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR); + m_atom = ::RegisterClass(&m_wc); + } + } + + lock.Unlock(); + } + + if (m_lpszOrigName != NULL) + { + ATLASSERT(pProc != NULL); + ATLASSERT(pWndProc != NULL); + *pProc = pWndProc; + } + + return m_atom; + } +#endif // _WIN32_WCE +}; + + +/////////////////////////////////////////////////////////////////////////////// +// Macros for declaring frame window WNDCLASS + +#ifndef _WIN32_WCE + +#define DECLARE_FRAME_WND_CLASS(WndClassName, uCommonResourceID) \ +static WTL::CFrameWndClassInfo& GetWndClassInfo() \ +{ \ + static WTL::CFrameWndClassInfo wc = \ + { \ + { sizeof(WNDCLASSEX), 0, StartWindowProc, \ + 0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName, NULL }, \ + NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \ + }; \ + return wc; \ +} + +#define DECLARE_FRAME_WND_CLASS_EX(WndClassName, uCommonResourceID, style, bkgnd) \ +static WTL::CFrameWndClassInfo& GetWndClassInfo() \ +{ \ + static WTL::CFrameWndClassInfo wc = \ + { \ + { sizeof(WNDCLASSEX), style, StartWindowProc, \ + 0, 0, NULL, NULL, NULL, (HBRUSH)(bkgnd + 1), NULL, WndClassName, NULL }, \ + NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \ + }; \ + return wc; \ +} + +#define DECLARE_FRAME_WND_SUPERCLASS(WndClassName, OrigWndClassName, uCommonResourceID) \ +static WTL::CFrameWndClassInfo& GetWndClassInfo() \ +{ \ + static WTL::CFrameWndClassInfo wc = \ + { \ + { sizeof(WNDCLASSEX), 0, StartWindowProc, \ + 0, 0, NULL, NULL, NULL, NULL, NULL, WndClassName, NULL }, \ + OrigWndClassName, NULL, NULL, TRUE, 0, _T(""), uCommonResourceID \ + }; \ + return wc; \ +} + +#else // CE specific + +#define DECLARE_FRAME_WND_CLASS(WndClassName, uCommonResourceID) \ +static WTL::CFrameWndClassInfo& GetWndClassInfo() \ +{ \ + static WTL::CFrameWndClassInfo wc = \ + { \ + { 0, StartWindowProc, \ + 0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName }, \ + NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \ + }; \ + return wc; \ +} + +#define DECLARE_FRAME_WND_CLASS_EX(WndClassName, uCommonResourceID, style, bkgnd) \ +static WTL::CFrameWndClassInfo& GetWndClassInfo() \ +{ \ + static WTL::CFrameWndClassInfo wc = \ + { \ + { style, StartWindowProc, \ + 0, 0, NULL, NULL, NULL, (HBRUSH)(bkgnd + 1), NULL, WndClassName }, \ + NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \ + }; \ + return wc; \ +} + +#define DECLARE_FRAME_WND_SUPERCLASS(WndClassName, OrigWndClassName, uCommonResourceID) \ +static WTL::CFrameWndClassInfo& GetWndClassInfo() \ +{ \ + static WTL::CFrameWndClassInfo wc = \ + { \ + { NULL, StartWindowProc, \ + 0, 0, NULL, NULL, NULL, NULL, NULL, WndClassName }, \ + OrigWndClassName, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \ + }; \ + return wc; \ +} + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CFrameWindowImpl + +// Client window command chaining macro (only for frame windows) +#define CHAIN_CLIENT_COMMANDS() \ + if(uMsg == WM_COMMAND && m_hWndClient != NULL) \ + ::SendMessage(m_hWndClient, uMsg, wParam, lParam); + +// standard toolbar styles +#define ATL_SIMPLE_TOOLBAR_STYLE \ + (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS) +// toolbar in a rebar pane +#define ATL_SIMPLE_TOOLBAR_PANE_STYLE \ + (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIGN | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT) +// standard rebar styles +#if (_WIN32_IE >= 0x0400) + #define ATL_SIMPLE_REBAR_STYLE \ + (WS_CHILD | WS_VISIBLE | WS_BORDER | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS | RBS_AUTOSIZE) +#else + #define ATL_SIMPLE_REBAR_STYLE \ + (WS_CHILD | WS_VISIBLE | WS_BORDER | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS) +#endif // !(_WIN32_IE >= 0x0400) +// rebar without borders +#if (_WIN32_IE >= 0x0400) + #define ATL_SIMPLE_REBAR_NOBORDER_STYLE \ + (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS | RBS_AUTOSIZE | CCS_NODIVIDER) +#else + #define ATL_SIMPLE_REBAR_NOBORDER_STYLE \ + (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS | CCS_NODIVIDER) +#endif // !(_WIN32_IE >= 0x0400) + +// command bar support +#if !defined(__ATLCTRLW_H__) && !defined(_WIN32_WCE) + +#define CBRM_GETCMDBAR (WM_USER + 301) // returns command bar HWND +#define CBRM_GETMENU (WM_USER + 302) // returns loaded or attached menu +#define CBRM_TRACKPOPUPMENU (WM_USER + 303) // displays a popup menu + +struct _AtlFrameWnd_CmdBarPopupMenu +{ + int cbSize; + HMENU hMenu; + UINT uFlags; + int x; + int y; + LPTPMPARAMS lptpm; +}; + +#define CBRPOPUPMENU _AtlFrameWnd_CmdBarPopupMenu + +#endif // !defined(__ATLCTRLW_H__) && !defined(_WIN32_WCE) + + +template +class ATL_NO_VTABLE CFrameWindowImplBase : public ATL::CWindowImplBaseT< TBase, TWinTraits > +{ +public: + DECLARE_FRAME_WND_CLASS(NULL, 0) + +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + struct _ChevronMenuInfo + { + HMENU hMenu; + LPNMREBARCHEVRON lpnm; + bool bCmdBar; + }; +#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + +// Data members + HWND m_hWndToolBar; + HWND m_hWndStatusBar; + HWND m_hWndClient; + +#ifdef _WIN32_WCE + HWND m_hWndCECommandBar; +#endif // _WIN32_WCE + + HACCEL m_hAccel; + +// Constructor + CFrameWindowImplBase() : + m_hWndToolBar(NULL), + m_hWndStatusBar(NULL), + m_hWndClient(NULL), +#ifdef _WIN32_WCE + m_hWndCECommandBar(NULL), +#endif // _WIN32_WCE + m_hAccel(NULL) + { } + +// Methods + HWND Create(HWND hWndParent, ATL::_U_RECT rect, LPCTSTR szWindowName, DWORD dwStyle, DWORD dwExStyle, ATL::_U_MENUorID MenuOrID, ATOM atom, LPVOID lpCreateParam) + { + ATLASSERT(m_hWnd == NULL); + + if(atom == 0) + return NULL; + + ModuleHelper::AddCreateWndData(&m_thunk.cd, this); + + if(MenuOrID.m_hMenu == NULL && (dwStyle & WS_CHILD)) + MenuOrID.m_hMenu = (HMENU)(UINT_PTR)this; + if(rect.m_lpRect == NULL) + rect.m_lpRect = &TBase::rcDefault; + + HWND hWnd = ::CreateWindowEx(dwExStyle, MAKEINTATOM(atom), szWindowName, + dwStyle, rect.m_lpRect->left, rect.m_lpRect->top, rect.m_lpRect->right - rect.m_lpRect->left, + rect.m_lpRect->bottom - rect.m_lpRect->top, hWndParent, MenuOrID.m_hMenu, + ModuleHelper::GetModuleInstance(), lpCreateParam); + + ATLASSERT(hWnd == NULL || m_hWnd == hWnd); + + return hWnd; + } + + static HWND CreateSimpleToolBarCtrl(HWND hWndParent, UINT nResourceID, BOOL bInitialSeparator = FALSE, + DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) + { + HINSTANCE hInst = ModuleHelper::GetResourceInstance(); + HRSRC hRsrc = ::FindResource(hInst, MAKEINTRESOURCE(nResourceID), RT_TOOLBAR); + if (hRsrc == NULL) + return NULL; + + HGLOBAL hGlobal = ::LoadResource(hInst, hRsrc); + if (hGlobal == NULL) + return NULL; + + _AtlToolBarData* pData = (_AtlToolBarData*)::LockResource(hGlobal); + if (pData == NULL) + return NULL; + ATLASSERT(pData->wVersion == 1); + + WORD* pItems = pData->items(); + int nItems = pData->wItemCount + (bInitialSeparator ? 1 : 0); + CTempBuffer buff; + TBBUTTON* pTBBtn = buff.Allocate(nItems); + ATLASSERT(pTBBtn != NULL); + if(pTBBtn == NULL) + return NULL; + + const int cxSeparator = 8; + + // set initial separator (half width) + if(bInitialSeparator) + { + pTBBtn[0].iBitmap = cxSeparator / 2; + pTBBtn[0].idCommand = 0; + pTBBtn[0].fsState = 0; + pTBBtn[0].fsStyle = TBSTYLE_SEP; + pTBBtn[0].dwData = 0; + pTBBtn[0].iString = 0; + } + + int nBmp = 0; + for(int i = 0, j = bInitialSeparator ? 1 : 0; i < pData->wItemCount; i++, j++) + { + if(pItems[i] != 0) + { + pTBBtn[j].iBitmap = nBmp++; + pTBBtn[j].idCommand = pItems[i]; + pTBBtn[j].fsState = TBSTATE_ENABLED; + pTBBtn[j].fsStyle = TBSTYLE_BUTTON; + pTBBtn[j].dwData = 0; + pTBBtn[j].iString = 0; + } + else + { + pTBBtn[j].iBitmap = cxSeparator; + pTBBtn[j].idCommand = 0; + pTBBtn[j].fsState = 0; + pTBBtn[j].fsStyle = TBSTYLE_SEP; + pTBBtn[j].dwData = 0; + pTBBtn[j].iString = 0; + } + } + +#ifndef _WIN32_WCE + HWND hWnd = ::CreateWindowEx(0, TOOLBARCLASSNAME, NULL, dwStyle, 0, 0, 100, 100, hWndParent, (HMENU)LongToHandle(nID), ModuleHelper::GetModuleInstance(), NULL); + if(hWnd == NULL) + { + ATLASSERT(FALSE); + return NULL; + } +#else // CE specific + dwStyle; + nID; + // The toolbar must go onto the existing CommandBar or MenuBar + HWND hWnd = hWndParent; +#endif // _WIN32_WCE + + ::SendMessage(hWnd, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0L); + + // check if font is taller than our bitmaps + CFontHandle font = (HFONT)::SendMessage(hWnd, WM_GETFONT, 0, 0L); + if(font.IsNull()) + font = (HFONT)::GetStockObject(SYSTEM_FONT); + LOGFONT lf = { 0 }; + font.GetLogFont(lf); + WORD cyFontHeight = (WORD)abs(lf.lfHeight); + +#ifndef _WIN32_WCE + WORD bitsPerPixel = AtlGetBitmapResourceBitsPerPixel(nResourceID); + if(bitsPerPixel > 4) + { + COLORREF crMask = CLR_DEFAULT; + if(bitsPerPixel == 32) + { + // 32-bit color bitmap with alpha channel (valid for Windows XP and later) + crMask = CLR_NONE; + } + HIMAGELIST hImageList = ImageList_LoadImage(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(nResourceID), pData->wWidth, 1, crMask, IMAGE_BITMAP, LR_CREATEDIBSECTION | LR_DEFAULTSIZE); + ATLASSERT(hImageList != NULL); + ::SendMessage(hWnd, TB_SETIMAGELIST, 0, (LPARAM)hImageList); + } + else +#endif // !_WIN32_WCE + { + TBADDBITMAP tbab = { 0 }; + tbab.hInst = hInst; + tbab.nID = nResourceID; + ::SendMessage(hWnd, TB_ADDBITMAP, nBmp, (LPARAM)&tbab); + } + + ::SendMessage(hWnd, TB_ADDBUTTONS, nItems, (LPARAM)pTBBtn); + ::SendMessage(hWnd, TB_SETBITMAPSIZE, 0, MAKELONG(pData->wWidth, max(pData->wHeight, cyFontHeight))); + const int cxyButtonMargin = 7; + ::SendMessage(hWnd, TB_SETBUTTONSIZE, 0, MAKELONG(pData->wWidth + cxyButtonMargin, max(pData->wHeight, cyFontHeight) + cxyButtonMargin)); + + return hWnd; + } + +#ifndef _WIN32_WCE + static HWND CreateSimpleReBarCtrl(HWND hWndParent, DWORD dwStyle = ATL_SIMPLE_REBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) + { + // Ensure style combinations for proper rebar painting + if(dwStyle & CCS_NODIVIDER && dwStyle & WS_BORDER) + dwStyle &= ~WS_BORDER; + else if(!(dwStyle & WS_BORDER) && !(dwStyle & CCS_NODIVIDER)) + dwStyle |= CCS_NODIVIDER; + + // Create rebar window + HWND hWndReBar = ::CreateWindowEx(0, REBARCLASSNAME, NULL, dwStyle, 0, 0, 100, 100, hWndParent, (HMENU)LongToHandle(nID), ModuleHelper::GetModuleInstance(), NULL); + if(hWndReBar == NULL) + { + ATLTRACE2(atlTraceUI, 0, _T("Failed to create rebar.\n")); + return NULL; + } + + // Initialize and send the REBARINFO structure + REBARINFO rbi = { 0 }; + rbi.cbSize = sizeof(REBARINFO); + rbi.fMask = 0; + if(!::SendMessage(hWndReBar, RB_SETBARINFO, 0, (LPARAM)&rbi)) + { + ATLTRACE2(atlTraceUI, 0, _T("Failed to initialize rebar.\n")); + ::DestroyWindow(hWndReBar); + return NULL; + } + + return hWndReBar; + } + + BOOL CreateSimpleReBar(DWORD dwStyle = ATL_SIMPLE_REBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) + { + ATLASSERT(!::IsWindow(m_hWndToolBar)); + m_hWndToolBar = CreateSimpleReBarCtrl(m_hWnd, dwStyle, nID); + return (m_hWndToolBar != NULL); + } + + static BOOL AddSimpleReBarBandCtrl(HWND hWndReBar, HWND hWndBand, int nID = 0, LPCTSTR lpstrTitle = NULL, BOOL bNewRow = FALSE, int cxWidth = 0, BOOL bFullWidthAlways = FALSE) + { + ATLASSERT(::IsWindow(hWndReBar)); // must be already created +#ifdef _DEBUG + // block - check if this is really a rebar + { + TCHAR lpszClassName[sizeof(REBARCLASSNAME)] = { 0 }; + ::GetClassName(hWndReBar, lpszClassName, sizeof(REBARCLASSNAME)); + ATLASSERT(lstrcmp(lpszClassName, REBARCLASSNAME) == 0); + } +#endif // _DEBUG + ATLASSERT(::IsWindow(hWndBand)); // must be already created + + // Get number of buttons on the toolbar + int nBtnCount = (int)::SendMessage(hWndBand, TB_BUTTONCOUNT, 0, 0L); + + // Set band info structure + REBARBANDINFO rbBand = { RunTimeHelper::SizeOf_REBARBANDINFO() }; +#if (_WIN32_IE >= 0x0400) + rbBand.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_SIZE | RBBIM_IDEALSIZE; +#else + rbBand.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_SIZE; +#endif // !(_WIN32_IE >= 0x0400) + if(lpstrTitle != NULL) + rbBand.fMask |= RBBIM_TEXT; + rbBand.fStyle = RBBS_CHILDEDGE; +#if (_WIN32_IE >= 0x0500) + if(nBtnCount > 0) // add chevron style for toolbar with buttons + rbBand.fStyle |= RBBS_USECHEVRON; +#endif // (_WIN32_IE >= 0x0500) + if(bNewRow) + rbBand.fStyle |= RBBS_BREAK; + + rbBand.lpText = (LPTSTR)lpstrTitle; + rbBand.hwndChild = hWndBand; + if(nID == 0) // calc band ID + nID = ATL_IDW_BAND_FIRST + (int)::SendMessage(hWndReBar, RB_GETBANDCOUNT, 0, 0L); + rbBand.wID = nID; + + // Calculate the size of the band + BOOL bRet = FALSE; + RECT rcTmp = { 0 }; + if(nBtnCount > 0) + { + bRet = (BOOL)::SendMessage(hWndBand, TB_GETITEMRECT, nBtnCount - 1, (LPARAM)&rcTmp); + ATLASSERT(bRet); + rbBand.cx = (cxWidth != 0) ? cxWidth : rcTmp.right; + rbBand.cyMinChild = rcTmp.bottom - rcTmp.top; + if(bFullWidthAlways) + { + rbBand.cxMinChild = rbBand.cx; + } + else if(lpstrTitle == NULL) + { + bRet = (BOOL)::SendMessage(hWndBand, TB_GETITEMRECT, 0, (LPARAM)&rcTmp); + ATLASSERT(bRet); + rbBand.cxMinChild = rcTmp.right; + } + else + { + rbBand.cxMinChild = 0; + } + } + else // no buttons, either not a toolbar or really has no buttons + { + bRet = ::GetWindowRect(hWndBand, &rcTmp); + ATLASSERT(bRet); + rbBand.cx = (cxWidth != 0) ? cxWidth : (rcTmp.right - rcTmp.left); + rbBand.cxMinChild = bFullWidthAlways ? rbBand.cx : 0; + rbBand.cyMinChild = rcTmp.bottom - rcTmp.top; + } + +#if (_WIN32_IE >= 0x0400) + rbBand.cxIdeal = rbBand.cx; +#endif // (_WIN32_IE >= 0x0400) + + // Add the band + LRESULT lRes = ::SendMessage(hWndReBar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbBand); + if(lRes == 0) + { + ATLTRACE2(atlTraceUI, 0, _T("Failed to add a band to the rebar.\n")); + return FALSE; + } + +#if (_WIN32_IE >= 0x0501) + DWORD dwExStyle = (DWORD)::SendMessage(hWndBand, TB_GETEXTENDEDSTYLE, 0, 0L); + ::SendMessage(hWndBand, TB_SETEXTENDEDSTYLE, 0, dwExStyle | TBSTYLE_EX_HIDECLIPPEDBUTTONS); +#endif // (_WIN32_IE >= 0x0501) + + return TRUE; + } + + BOOL AddSimpleReBarBand(HWND hWndBand, LPCTSTR lpstrTitle = NULL, BOOL bNewRow = FALSE, int cxWidth = 0, BOOL bFullWidthAlways = FALSE) + { + ATLASSERT(::IsWindow(m_hWndToolBar)); // must be an existing rebar + ATLASSERT(::IsWindow(hWndBand)); // must be created + return AddSimpleReBarBandCtrl(m_hWndToolBar, hWndBand, 0, lpstrTitle, bNewRow, cxWidth, bFullWidthAlways); + } + +#if (_WIN32_IE >= 0x0400) + void SizeSimpleReBarBands() + { + ATLASSERT(::IsWindow(m_hWndToolBar)); // must be an existing rebar + + int nCount = (int)::SendMessage(m_hWndToolBar, RB_GETBANDCOUNT, 0, 0L); + + for(int i = 0; i < nCount; i++) + { + REBARBANDINFO rbBand = { RunTimeHelper::SizeOf_REBARBANDINFO() }; + rbBand.fMask = RBBIM_SIZE; + BOOL bRet = (BOOL)::SendMessage(m_hWndToolBar, RB_GETBANDINFO, i, (LPARAM)&rbBand); + ATLASSERT(bRet); + RECT rect = { 0, 0, 0, 0 }; + ::SendMessage(m_hWndToolBar, RB_GETBANDBORDERS, i, (LPARAM)&rect); + rbBand.cx += rect.left + rect.right; + bRet = (BOOL)::SendMessage(m_hWndToolBar, RB_SETBANDINFO, i, (LPARAM)&rbBand); + ATLASSERT(bRet); + } + } +#endif // (_WIN32_IE >= 0x0400) +#endif // _WIN32_WCE + +#ifndef _WIN32_WCE + BOOL CreateSimpleStatusBar(LPCTSTR lpstrText, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR) +#else // CE specific + BOOL CreateSimpleStatusBar(LPCTSTR lpstrText, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, UINT nID = ATL_IDW_STATUS_BAR) +#endif // _WIN32_WCE + { + ATLASSERT(!::IsWindow(m_hWndStatusBar)); + m_hWndStatusBar = ::CreateStatusWindow(dwStyle, lpstrText, m_hWnd, nID); + return (m_hWndStatusBar != NULL); + } + +#ifndef _WIN32_WCE + BOOL CreateSimpleStatusBar(UINT nTextID = ATL_IDS_IDLEMESSAGE, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR) +#else // CE specific + BOOL CreateSimpleStatusBar(UINT nTextID = ATL_IDS_IDLEMESSAGE, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, UINT nID = ATL_IDW_STATUS_BAR) +#endif // _WIN32_WCE + { + const int cchMax = 128; // max text length is 127 for status bars (+1 for null) + TCHAR szText[cchMax]; + szText[0] = 0; + ::LoadString(ModuleHelper::GetResourceInstance(), nTextID, szText, cchMax); + return CreateSimpleStatusBar(szText, dwStyle, nID); + } + +#ifdef _WIN32_WCE + BOOL CreateSimpleCECommandBar(LPTSTR pszMenu = NULL, WORD iButton = 0, DWORD dwFlags = 0, int nCmdBarID = 1) + { + ATLASSERT(m_hWndCECommandBar == NULL); + ATLASSERT(m_hWndToolBar == NULL); + + m_hWndCECommandBar = ::CommandBar_Create(ModuleHelper::GetModuleInstance(), m_hWnd, nCmdBarID); + if(m_hWndCECommandBar == NULL) + return FALSE; + + m_hWndToolBar = m_hWndCECommandBar; + + BOOL bRet = TRUE; + + if(pszMenu != NULL) + bRet &= ::CommandBar_InsertMenubarEx(m_hWndCECommandBar, IS_INTRESOURCE(pszMenu) ? ModuleHelper::GetResourceInstance() : NULL, pszMenu, iButton); + + bRet &= ::CommandBar_AddAdornments(m_hWndCECommandBar, dwFlags, 0); + + return bRet; + } + +#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) + BOOL CreateSimpleCEMenuBar(UINT nToolBarId = ATL_IDW_MENU_BAR, DWORD dwFlags = 0, int nBmpId = 0, int cBmpImages = 0) + { + ATLASSERT(m_hWndCECommandBar == NULL); + + SHMENUBARINFO mbi = { 0 }; + mbi.cbSize = sizeof(mbi); + mbi.hwndParent = m_hWnd; + mbi.dwFlags = dwFlags; + mbi.nToolBarId = nToolBarId; + mbi.hInstRes = ModuleHelper::GetResourceInstance(); + mbi.nBmpId = nBmpId; + mbi.cBmpImages = cBmpImages; + mbi.hwndMB = NULL; // This gets set by SHCreateMenuBar + + BOOL bRet = ::SHCreateMenuBar(&mbi); + if(bRet != FALSE) + { + m_hWndCECommandBar = mbi.hwndMB; + SizeToMenuBar(); + } + + return bRet; + } + + void SizeToMenuBar() // for menu bar only + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(::IsWindow(m_hWndCECommandBar)); + + RECT rect = { 0 }; + GetWindowRect(&rect); + RECT rectMB = { 0 }; + ::GetWindowRect(m_hWndCECommandBar, &rectMB); + int cy = ::IsWindowVisible(m_hWndCECommandBar) ? rectMB.top - rect.top : rectMB.bottom - rect.top; + SetWindowPos(NULL, 0, 0, rect.right - rect.left, cy, SWP_NOZORDER | SWP_NOMOVE); + } +#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) +#endif // _WIN32_WCE + + void UpdateLayout(BOOL bResizeBars = TRUE) + { + RECT rect = { 0 }; + GetClientRect(&rect); + + // position bars and offset their dimensions + UpdateBarsPosition(rect, bResizeBars); + + // resize client window + if(m_hWndClient != NULL) + ::SetWindowPos(m_hWndClient, NULL, rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + SWP_NOZORDER | SWP_NOACTIVATE); + } + + void UpdateBarsPosition(RECT& rect, BOOL bResizeBars = TRUE) + { + // resize toolbar + if(m_hWndToolBar != NULL && ((DWORD)::GetWindowLong(m_hWndToolBar, GWL_STYLE) & WS_VISIBLE)) + { + if(bResizeBars != FALSE) + { + ::SendMessage(m_hWndToolBar, WM_SIZE, 0, 0); + ::InvalidateRect(m_hWndToolBar, NULL, TRUE); + } + RECT rectTB = { 0 }; + ::GetWindowRect(m_hWndToolBar, &rectTB); + rect.top += rectTB.bottom - rectTB.top; + } + + // resize status bar + if(m_hWndStatusBar != NULL && ((DWORD)::GetWindowLong(m_hWndStatusBar, GWL_STYLE) & WS_VISIBLE)) + { + if(bResizeBars != FALSE) + ::SendMessage(m_hWndStatusBar, WM_SIZE, 0, 0); + RECT rectSB = { 0 }; + ::GetWindowRect(m_hWndStatusBar, &rectSB); + rect.bottom -= rectSB.bottom - rectSB.top; + } + } + + BOOL PreTranslateMessage(MSG* pMsg) + { + if(m_hAccel != NULL && ::TranslateAccelerator(m_hWnd, m_hAccel, pMsg)) + return TRUE; + return FALSE; + } + + BEGIN_MSG_MAP(CFrameWindowImplBase) + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) +#ifndef _WIN32_WCE + MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect) +#endif // !_WIN32_WCE + MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) + MESSAGE_HANDLER(WM_DESTROY, OnDestroy) +#ifndef _WIN32_WCE + NOTIFY_CODE_HANDLER(TTN_GETDISPINFOA, OnToolTipTextA) + NOTIFY_CODE_HANDLER(TTN_GETDISPINFOW, OnToolTipTextW) +#endif // !_WIN32_WCE + END_MSG_MAP() + + LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if(m_hWndClient != NULL) // view will paint itself instead + return 1; + + bHandled = FALSE; + return 0; + } + +#ifndef _WIN32_WCE + LRESULT OnMenuSelect(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + bHandled = FALSE; + + if(m_hWndStatusBar == NULL) + return 1; + + WORD wFlags = HIWORD(wParam); + if(wFlags == 0xFFFF && lParam == NULL) // menu closing + { + ::SendMessage(m_hWndStatusBar, SB_SIMPLE, FALSE, 0L); + } + else + { + const int cchBuff = 256; + TCHAR szBuff[cchBuff]; + szBuff[0] = 0; + if(!(wFlags & MF_POPUP)) + { + WORD wID = LOWORD(wParam); + // check for special cases + if(wID >= 0xF000 && wID < 0xF1F0) // system menu IDs + wID = (WORD)(((wID - 0xF000) >> 4) + ATL_IDS_SCFIRST); + else if(wID >= ID_FILE_MRU_FIRST && wID <= ID_FILE_MRU_LAST) // MRU items + wID = ATL_IDS_MRU_FILE; + else if(wID >= ATL_IDM_FIRST_MDICHILD && wID <= ATL_IDM_LAST_MDICHILD) // MDI child windows + wID = ATL_IDS_MDICHILD; + + int nRet = ::LoadString(ModuleHelper::GetResourceInstance(), wID, szBuff, cchBuff); + for(int i = 0; i < nRet; i++) + { + if(szBuff[i] == _T('\n')) + { + szBuff[i] = 0; + break; + } + } + } + ::SendMessage(m_hWndStatusBar, SB_SIMPLE, TRUE, 0L); + ::SendMessage(m_hWndStatusBar, SB_SETTEXT, (255 | SBT_NOBORDERS), (LPARAM)szBuff); + } + + return 1; + } +#endif // !_WIN32_WCE + + LRESULT OnSetFocus(UINT, WPARAM, LPARAM, BOOL& bHandled) + { + if(m_hWndClient != NULL) + ::SetFocus(m_hWndClient); + + bHandled = FALSE; + return 1; + } + + LRESULT OnDestroy(UINT, WPARAM, LPARAM, BOOL& bHandled) + { + if((GetStyle() & (WS_CHILD | WS_POPUP)) == 0) + ::PostQuitMessage(1); + + bHandled = FALSE; + return 1; + } + +#ifndef _WIN32_WCE + LRESULT OnToolTipTextA(int idCtrl, LPNMHDR pnmh, BOOL& /*bHandled*/) + { + LPNMTTDISPINFOA pDispInfo = (LPNMTTDISPINFOA)pnmh; + pDispInfo->szText[0] = 0; + + if((idCtrl != 0) && !(pDispInfo->uFlags & TTF_IDISHWND)) + { + const int cchBuff = 256; + char szBuff[cchBuff]; + szBuff[0] = 0; + int nRet = ::LoadStringA(ModuleHelper::GetResourceInstance(), idCtrl, szBuff, cchBuff); + for(int i = 0; i < nRet; i++) + { + if(szBuff[i] == '\n') + { + SecureHelper::strncpyA_x(pDispInfo->szText, _countof(pDispInfo->szText), &szBuff[i + 1], _TRUNCATE); + break; + } + } +#if (_WIN32_IE >= 0x0300) + if(nRet > 0) // string was loaded, save it + pDispInfo->uFlags |= TTF_DI_SETITEM; +#endif // (_WIN32_IE >= 0x0300) + } + + return 0; + } + + LRESULT OnToolTipTextW(int idCtrl, LPNMHDR pnmh, BOOL& /*bHandled*/) + { + LPNMTTDISPINFOW pDispInfo = (LPNMTTDISPINFOW)pnmh; + pDispInfo->szText[0] = 0; + + if((idCtrl != 0) && !(pDispInfo->uFlags & TTF_IDISHWND)) + { + const int cchBuff = 256; + wchar_t szBuff[cchBuff]; + szBuff[0] = 0; + int nRet = ::LoadStringW(ModuleHelper::GetResourceInstance(), idCtrl, szBuff, cchBuff); + for(int i = 0; i < nRet; i++) + { + if(szBuff[i] == L'\n') + { + SecureHelper::strncpyW_x(pDispInfo->szText, _countof(pDispInfo->szText), &szBuff[i + 1], _TRUNCATE); + break; + } + } +#if (_WIN32_IE >= 0x0300) + if(nRet > 0) // string was loaded, save it + pDispInfo->uFlags |= TTF_DI_SETITEM; +#endif // (_WIN32_IE >= 0x0300) + } + + return 0; + } +#endif // !_WIN32_WCE + +// Implementation - chevron menu support +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + bool PrepareChevronMenu(_ChevronMenuInfo& cmi) + { + // get rebar and toolbar + REBARBANDINFO rbbi = { RunTimeHelper::SizeOf_REBARBANDINFO() }; + rbbi.fMask = RBBIM_CHILD; + BOOL bRet = (BOOL)::SendMessage(cmi.lpnm->hdr.hwndFrom, RB_GETBANDINFO, cmi.lpnm->uBand, (LPARAM)&rbbi); + ATLASSERT(bRet); + + // assume the band is a toolbar + ATL::CWindow wnd = rbbi.hwndChild; + int nCount = (int)wnd.SendMessage(TB_BUTTONCOUNT); + if(nCount <= 0) // probably not a toolbar + return false; + + // check if it's a command bar + CMenuHandle menuCmdBar = (HMENU)wnd.SendMessage(CBRM_GETMENU); + cmi.bCmdBar = (menuCmdBar.m_hMenu != NULL); + + // build a menu from hidden items + CMenuHandle menu; + bRet = menu.CreatePopupMenu(); + ATLASSERT(bRet); + RECT rcClient = { 0 }; + bRet = wnd.GetClientRect(&rcClient); + ATLASSERT(bRet); + for(int i = 0; i < nCount; i++) + { + TBBUTTON tbb = { 0 }; + bRet = (BOOL)wnd.SendMessage(TB_GETBUTTON, i, (LPARAM)&tbb); + ATLASSERT(bRet); + // skip hidden buttons + if((tbb.fsState & TBSTATE_HIDDEN) != 0) + continue; + RECT rcButton = { 0 }; + bRet = (BOOL)wnd.SendMessage(TB_GETITEMRECT, i, (LPARAM)&rcButton); + ATLASSERT(bRet); + bool bEnabled = ((tbb.fsState & TBSTATE_ENABLED) != 0); + if(rcButton.right > rcClient.right) + { + if(tbb.fsStyle & BTNS_SEP) + { + if(menu.GetMenuItemCount() > 0) + menu.AppendMenu(MF_SEPARATOR); + } + else if(cmi.bCmdBar) + { + const int cchBuff = 200; + TCHAR szBuff[cchBuff] = { 0 }; + CMenuItemInfo mii; + mii.fMask = MIIM_TYPE | MIIM_SUBMENU; + mii.dwTypeData = szBuff; + mii.cch = cchBuff; + bRet = menuCmdBar.GetMenuItemInfo(i, TRUE, &mii); + ATLASSERT(bRet); + // Note: CmdBar currently supports only drop-down items + ATLASSERT(::IsMenu(mii.hSubMenu)); + bRet = menu.AppendMenu(MF_STRING | MF_POPUP | (bEnabled ? MF_ENABLED : MF_GRAYED), (UINT_PTR)mii.hSubMenu, mii.dwTypeData); + ATLASSERT(bRet); + } + else + { + // get button's text + const int cchBuff = 200; + TCHAR szBuff[cchBuff] = { 0 }; + LPTSTR lpstrText = szBuff; + TBBUTTONINFO tbbi = { 0 }; + tbbi.cbSize = sizeof(TBBUTTONINFO); + tbbi.dwMask = TBIF_TEXT; + tbbi.pszText = szBuff; + tbbi.cchText = cchBuff; + if(wnd.SendMessage(TB_GETBUTTONINFO, tbb.idCommand, (LPARAM)&tbbi) == -1 || lstrlen(szBuff) == 0) + { + // no text for this button, try a resource string + lpstrText = _T(""); + int nRet = ::LoadString(ModuleHelper::GetResourceInstance(), tbb.idCommand, szBuff, cchBuff); + for(int n = 0; n < nRet; n++) + { + if(szBuff[n] == _T('\n')) + { + lpstrText = &szBuff[n + 1]; + break; + } + } + } + bRet = menu.AppendMenu(MF_STRING | (bEnabled ? MF_ENABLED : MF_GRAYED), tbb.idCommand, lpstrText); + ATLASSERT(bRet); + } + } + } + + if(menu.GetMenuItemCount() == 0) // no hidden buttons after all + { + menu.DestroyMenu(); + ::MessageBeep((UINT)-1); + return false; + } + + cmi.hMenu = menu; + return true; + } + + void DisplayChevronMenu(_ChevronMenuInfo& cmi) + { +#ifndef TPM_VERPOSANIMATION + const UINT TPM_VERPOSANIMATION = 0x1000L; // Menu animation flag +#endif + // convert chevron rect to screen coordinates + ATL::CWindow wndFrom = cmi.lpnm->hdr.hwndFrom; + POINT pt = { cmi.lpnm->rc.left, cmi.lpnm->rc.bottom }; + wndFrom.MapWindowPoints(NULL, &pt, 1); + RECT rc = cmi.lpnm->rc; + wndFrom.MapWindowPoints(NULL, &rc); + // set up flags and rect + UINT uMenuFlags = TPM_LEFTBUTTON | TPM_VERTICAL | TPM_LEFTALIGN | TPM_TOPALIGN | (!AtlIsOldWindows() ? TPM_VERPOSANIMATION : 0); + TPMPARAMS TPMParams = { 0 }; + TPMParams.cbSize = sizeof(TPMPARAMS); + TPMParams.rcExclude = rc; + // check if this window has a command bar + HWND hWndCmdBar = (HWND)::SendMessage(m_hWnd, CBRM_GETCMDBAR, 0, 0L); + if(::IsWindow(hWndCmdBar)) + { + CBRPOPUPMENU CBRPopupMenu = { sizeof(CBRPOPUPMENU), cmi.hMenu, uMenuFlags, pt.x, pt.y, &TPMParams }; + ::SendMessage(hWndCmdBar, CBRM_TRACKPOPUPMENU, 0, (LPARAM)&CBRPopupMenu); + } + else + { + CMenuHandle menu = cmi.hMenu; + menu.TrackPopupMenuEx(uMenuFlags, pt.x, pt.y, m_hWnd, &TPMParams); + } + } + + void CleanupChevronMenu(_ChevronMenuInfo& cmi) + { + CMenuHandle menu = cmi.hMenu; + // if menu is from a command bar, detach submenus so they are not destroyed + if(cmi.bCmdBar) + { + for(int i = menu.GetMenuItemCount() - 1; i >=0; i--) + menu.RemoveMenu(i, MF_BYPOSITION); + } + // destroy menu + menu.DestroyMenu(); + // convert chevron rect to screen coordinates + ATL::CWindow wndFrom = cmi.lpnm->hdr.hwndFrom; + RECT rc = cmi.lpnm->rc; + wndFrom.MapWindowPoints(NULL, &rc); + // eat next message if click is on the same button + MSG msg = { 0 }; + if(::PeekMessage(&msg, m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_NOREMOVE) && ::PtInRect(&rc, msg.pt)) + ::PeekMessage(&msg, m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_REMOVE); + } +#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) +}; + + +template +class ATL_NO_VTABLE CFrameWindowImpl : public CFrameWindowImplBase< TBase, TWinTraits > +{ +public: + HWND Create(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + HMENU hMenu = NULL, LPVOID lpCreateParam = NULL) + { + ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc); + + dwStyle = T::GetWndStyle(dwStyle); + dwExStyle = T::GetWndExStyle(dwExStyle); + + if(rect.m_lpRect == NULL) + rect.m_lpRect = &TBase::rcDefault; + + return CFrameWindowImplBase< TBase, TWinTraits >::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, hMenu, atom, lpCreateParam); + } + + HWND CreateEx(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL) + { + const int cchName = 256; + TCHAR szWindowName[cchName]; + szWindowName[0] = 0; +#ifndef _WIN32_WCE + ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName); + HMENU hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID)); +#else // CE specific + ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName); + + // This always needs to be NULL for Windows CE. + // Frame Window menus have to go onto the CommandBar. + // Use CreateSimpleCECommandBar + HMENU hMenu = NULL; +#endif // _WIN32_WCE + + T* pT = static_cast(this); + HWND hWnd = pT->Create(hWndParent, rect, szWindowName, dwStyle, dwExStyle, hMenu, lpCreateParam); + + if(hWnd != NULL) + m_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID)); + + return hWnd; + } + + BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) + { + if(nResourceID == 0) + nResourceID = T::GetWndClassInfo().m_uCommonResourceID; +#ifndef _WIN32_WCE + ATLASSERT(!::IsWindow(m_hWndToolBar)); + m_hWndToolBar = T::CreateSimpleToolBarCtrl(m_hWnd, nResourceID, TRUE, dwStyle, nID); + return (m_hWndToolBar != NULL); +#else // CE specific + HWND hWnd= T::CreateSimpleToolBarCtrl(m_hWndCECommandBar, nResourceID, TRUE, dwStyle, nID); + return (hWnd != NULL); +#endif // _WIN32_WCE + } + +#ifdef _WIN32_WCE + // CE specific variant that returns the handle of the toolbar + HWND CreateSimpleCEToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) + { + if(nResourceID == 0) + nResourceID = T::GetWndClassInfo().m_uCommonResourceID; + + return T::CreateSimpleToolBarCtrl(m_hWndCECommandBar, nResourceID, TRUE, dwStyle, nID); + } +#endif // _WIN32_WCE + +// message map and handlers + typedef CFrameWindowImplBase< TBase, TWinTraits > _baseClass; + + BEGIN_MSG_MAP(CFrameWindowImpl) + MESSAGE_HANDLER(WM_SIZE, OnSize) +#ifndef _ATL_NO_REBAR_SUPPORT +#if (_WIN32_IE >= 0x0400) + NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnReBarAutoSize) +#endif // (_WIN32_IE >= 0x0400) +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + NOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed) +#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) +#endif // !_ATL_NO_REBAR_SUPPORT + CHAIN_MSG_MAP(_baseClass) + END_MSG_MAP() + + LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + if(wParam != SIZE_MINIMIZED) + { + T* pT = static_cast(this); + pT->UpdateLayout(); + } + bHandled = FALSE; + return 1; + } + +#ifndef _ATL_NO_REBAR_SUPPORT +#if (_WIN32_IE >= 0x0400) + LRESULT OnReBarAutoSize(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->UpdateLayout(FALSE); + return 0; + } +#endif // (_WIN32_IE >= 0x0400) + +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + LRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) + { + T* pT = static_cast(this); + _ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false }; + if(!pT->PrepareChevronMenu(cmi)) + { + bHandled = FALSE; + return 1; + } + // display a popup menu with hidden items + pT->DisplayChevronMenu(cmi); + // cleanup + pT->CleanupChevronMenu(cmi); + return 0; + } +#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) +#endif // !_ATL_NO_REBAR_SUPPORT +}; + + +/////////////////////////////////////////////////////////////////////////////// +// AtlCreateSimpleToolBar - helper for creating simple toolbars + +#ifndef _WIN32_WCE + +inline HWND AtlCreateSimpleToolBar(HWND hWndParent, UINT nResourceID, BOOL bInitialSeparator = FALSE, + DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) +{ + return CFrameWindowImplBase<>::CreateSimpleToolBarCtrl(hWndParent, nResourceID, bInitialSeparator, dwStyle, nID); +} + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CMDIWindow + +#ifndef _WIN32_WCE + +#ifndef _WTL_MDIWINDOWMENU_TEXT +#define _WTL_MDIWINDOWMENU_TEXT _T("&Window") +#endif + +class CMDIWindow : public ATL::CWindow +{ +public: +// Data members + HWND m_hWndMDIClient; + HMENU m_hMenu; + +// Constructors + CMDIWindow(HWND hWnd = NULL) : ATL::CWindow(hWnd), m_hWndMDIClient(NULL), m_hMenu(NULL) + { } + + CMDIWindow& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + +// Operations + HWND MDIGetActive(BOOL* lpbMaximized = NULL) + { + ATLASSERT(::IsWindow(m_hWndMDIClient)); + return (HWND)::SendMessage(m_hWndMDIClient, WM_MDIGETACTIVE, 0, (LPARAM)lpbMaximized); + } + + void MDIActivate(HWND hWndChildToActivate) + { + ATLASSERT(::IsWindow(m_hWndMDIClient)); + ATLASSERT(::IsWindow(hWndChildToActivate)); + ::SendMessage(m_hWndMDIClient, WM_MDIACTIVATE, (WPARAM)hWndChildToActivate, 0); + } + + void MDINext(HWND hWndChild, BOOL bPrevious = FALSE) + { + ATLASSERT(::IsWindow(m_hWndMDIClient)); + ATLASSERT(hWndChild == NULL || ::IsWindow(hWndChild)); + ::SendMessage(m_hWndMDIClient, WM_MDINEXT, (WPARAM)hWndChild, (LPARAM)bPrevious); + } + + void MDIMaximize(HWND hWndChildToMaximize) + { + ATLASSERT(::IsWindow(m_hWndMDIClient)); + ATLASSERT(::IsWindow(hWndChildToMaximize)); + ::SendMessage(m_hWndMDIClient, WM_MDIMAXIMIZE, (WPARAM)hWndChildToMaximize, 0); + } + + void MDIRestore(HWND hWndChildToRestore) + { + ATLASSERT(::IsWindow(m_hWndMDIClient)); + ATLASSERT(::IsWindow(hWndChildToRestore)); + ::SendMessage(m_hWndMDIClient, WM_MDIRESTORE, (WPARAM)hWndChildToRestore, 0); + } + + void MDIDestroy(HWND hWndChildToDestroy) + { + ATLASSERT(::IsWindow(m_hWndMDIClient)); + ATLASSERT(::IsWindow(hWndChildToDestroy)); + ::SendMessage(m_hWndMDIClient, WM_MDIDESTROY, (WPARAM)hWndChildToDestroy, 0); + } + + BOOL MDICascade(UINT uFlags = 0) + { + ATLASSERT(::IsWindow(m_hWndMDIClient)); + return (BOOL)::SendMessage(m_hWndMDIClient, WM_MDICASCADE, (WPARAM)uFlags, 0); + } + + BOOL MDITile(UINT uFlags = MDITILE_HORIZONTAL) + { + ATLASSERT(::IsWindow(m_hWndMDIClient)); + return (BOOL)::SendMessage(m_hWndMDIClient, WM_MDITILE, (WPARAM)uFlags, 0); + } + + void MDIIconArrange() + { + ATLASSERT(::IsWindow(m_hWndMDIClient)); + ::SendMessage(m_hWndMDIClient, WM_MDIICONARRANGE, 0, 0); + } + + HMENU MDISetMenu(HMENU hMenuFrame, HMENU hMenuWindow) + { + ATLASSERT(::IsWindow(m_hWndMDIClient)); + return (HMENU)::SendMessage(m_hWndMDIClient, WM_MDISETMENU, (WPARAM)hMenuFrame, (LPARAM)hMenuWindow); + } + + HMENU MDIRefreshMenu() + { + ATLASSERT(::IsWindow(m_hWndMDIClient)); + return (HMENU)::SendMessage(m_hWndMDIClient, WM_MDIREFRESHMENU, 0, 0); + } + +// Additional operations + static HMENU GetStandardWindowMenu(HMENU hMenu) + { + int nCount = ::GetMenuItemCount(hMenu); + if(nCount == -1) + return NULL; + int nLen = ::GetMenuString(hMenu, nCount - 2, NULL, 0, MF_BYPOSITION); + if(nLen == 0) + return NULL; + CTempBuffer buff; + LPTSTR lpszText = buff.Allocate(nLen + 1); + if(lpszText == NULL) + return NULL; + if(::GetMenuString(hMenu, nCount - 2, lpszText, nLen + 1, MF_BYPOSITION) != nLen) + return NULL; + if(lstrcmp(lpszText, _WTL_MDIWINDOWMENU_TEXT) != 0) + return NULL; + return ::GetSubMenu(hMenu, nCount - 2); + } + + void SetMDIFrameMenu() + { + HMENU hWindowMenu = GetStandardWindowMenu(m_hMenu); + MDISetMenu(m_hMenu, hWindowMenu); + MDIRefreshMenu(); + ::DrawMenuBar(GetMDIFrame()); + } + + HWND GetMDIFrame() const + { + return ::GetParent(m_hWndMDIClient); + } +}; + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CMDIFrameWindowImpl + +#ifndef _WIN32_WCE + +// MDI child command chaining macro (only for MDI frame windows) +#define CHAIN_MDI_CHILD_COMMANDS() \ + if(uMsg == WM_COMMAND) \ + { \ + HWND hWndChild = MDIGetActive(); \ + if(hWndChild != NULL) \ + ::SendMessage(hWndChild, uMsg, wParam, lParam); \ + } + +template +class ATL_NO_VTABLE CMDIFrameWindowImpl : public CFrameWindowImplBase +{ +public: + HWND Create(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + HMENU hMenu = NULL, LPVOID lpCreateParam = NULL) + { + m_hMenu = hMenu; + ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc); + + dwStyle = T::GetWndStyle(dwStyle); + dwExStyle = T::GetWndExStyle(dwExStyle); + + if(rect.m_lpRect == NULL) + rect.m_lpRect = &TBase::rcDefault; + + return CFrameWindowImplBase::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, hMenu, atom, lpCreateParam); + } + + HWND CreateEx(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL) + { + const int cchName = 256; + TCHAR szWindowName[cchName]; + szWindowName[0] = 0; + ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName); + HMENU hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID)); + + T* pT = static_cast(this); + HWND hWnd = pT->Create(hWndParent, rect, szWindowName, dwStyle, dwExStyle, hMenu, lpCreateParam); + + if(hWnd != NULL) + m_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID)); + + return hWnd; + } + + BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) + { + ATLASSERT(!::IsWindow(m_hWndToolBar)); + if(nResourceID == 0) + nResourceID = T::GetWndClassInfo().m_uCommonResourceID; + m_hWndToolBar = T::CreateSimpleToolBarCtrl(m_hWnd, nResourceID, TRUE, dwStyle, nID); + return (m_hWndToolBar != NULL); + } + + virtual WNDPROC GetWindowProc() + { + return MDIFrameWindowProc; + } + + static LRESULT CALLBACK MDIFrameWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) + { + CMDIFrameWindowImpl< T, TBase, TWinTraits >* pThis = (CMDIFrameWindowImpl< T, TBase, TWinTraits >*)hWnd; + // set a ptr to this message and save the old value +#if (_ATL_VER >= 0x0700) + ATL::_ATL_MSG msg(pThis->m_hWnd, uMsg, wParam, lParam); + const ATL::_ATL_MSG* pOldMsg = pThis->m_pCurrentMsg; +#else // !(_ATL_VER >= 0x0700) + MSG msg = { pThis->m_hWnd, uMsg, wParam, lParam, 0, { 0, 0 } }; + const MSG* pOldMsg = pThis->m_pCurrentMsg; +#endif // !(_ATL_VER >= 0x0700) + pThis->m_pCurrentMsg = &msg; + // pass to the message map to process + LRESULT lRes = 0; + BOOL bRet = pThis->ProcessWindowMessage(pThis->m_hWnd, uMsg, wParam, lParam, lRes, 0); + // restore saved value for the current message + ATLASSERT(pThis->m_pCurrentMsg == &msg); + pThis->m_pCurrentMsg = pOldMsg; + // do the default processing if message was not handled + if(!bRet) + { + if(uMsg != WM_NCDESTROY) + lRes = pThis->DefWindowProc(uMsg, wParam, lParam); + else + { + // unsubclass, if needed + LONG_PTR pfnWndProc = ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC); + lRes = pThis->DefWindowProc(uMsg, wParam, lParam); + if(pThis->m_pfnSuperWindowProc != ::DefWindowProc && ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC) == pfnWndProc) + ::SetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC, (LONG_PTR)pThis->m_pfnSuperWindowProc); +#if (_ATL_VER >= 0x0700) + // mark window as destryed + pThis->m_dwState |= WINSTATE_DESTROYED; +#else // !(_ATL_VER >= 0x0700) + // clear out window handle + HWND hWnd = pThis->m_hWnd; + pThis->m_hWnd = NULL; + // clean up after window is destroyed + pThis->OnFinalMessage(hWnd); +#endif // !(_ATL_VER >= 0x0700) + } + } +#if (_ATL_VER >= 0x0700) + if(pThis->m_dwState & WINSTATE_DESTROYED && pThis->m_pCurrentMsg == NULL) + { + // clear out window handle + HWND hWnd = pThis->m_hWnd; + pThis->m_hWnd = NULL; + pThis->m_dwState &= ~WINSTATE_DESTROYED; + // clean up after window is destroyed + pThis->OnFinalMessage(hWnd); + } +#endif // (_ATL_VER >= 0x0700) + return lRes; + } + + // Overriden to call DefWindowProc which uses DefFrameProc + LRESULT DefWindowProc() + { + const MSG* pMsg = m_pCurrentMsg; + LRESULT lRes = 0; + if (pMsg != NULL) + lRes = DefWindowProc(pMsg->message, pMsg->wParam, pMsg->lParam); + return lRes; + } + + LRESULT DefWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam) + { + return ::DefFrameProc(m_hWnd, m_hWndMDIClient, uMsg, wParam, lParam); + } + + BOOL PreTranslateMessage(MSG* pMsg) + { + if(CFrameWindowImplBase::PreTranslateMessage(pMsg)) + return TRUE; + return ::TranslateMDISysAccel(m_hWndMDIClient, pMsg); + } + + HWND CreateMDIClient(HMENU hWindowMenu = NULL, UINT nID = ATL_IDW_CLIENT, UINT nFirstChildID = ATL_IDM_FIRST_MDICHILD) + { + DWORD dwStyle = WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | MDIS_ALLCHILDSTYLES; + DWORD dwExStyle = WS_EX_CLIENTEDGE; + + CLIENTCREATESTRUCT ccs = { 0 }; + ccs.hWindowMenu = hWindowMenu; + ccs.idFirstChild = nFirstChildID; + + if((GetStyle() & (WS_HSCROLL | WS_VSCROLL)) != 0) + { + // parent MDI frame's scroll styles move to the MDICLIENT + dwStyle |= (GetStyle() & (WS_HSCROLL | WS_VSCROLL)); + + // fast way to turn off the scrollbar bits (without a resize) + ModifyStyle(WS_HSCROLL | WS_VSCROLL, 0, SWP_NOREDRAW | SWP_FRAMECHANGED); + } + + // Create MDICLIENT window + m_hWndClient = ::CreateWindowEx(dwExStyle, _T("MDIClient"), NULL, + dwStyle, 0, 0, 1, 1, m_hWnd, (HMENU)LongToHandle(nID), + ModuleHelper::GetModuleInstance(), (LPVOID)&ccs); + if (m_hWndClient == NULL) + { + ATLTRACE2(atlTraceUI, 0, _T("MDI Frame failed to create MDICLIENT.\n")); + return NULL; + } + + // Move it to the top of z-order + ::BringWindowToTop(m_hWndClient); + + // set as MDI client window + m_hWndMDIClient = m_hWndClient; + + // update to proper size + T* pT = static_cast(this); + pT->UpdateLayout(); + + return m_hWndClient; + } + + typedef CFrameWindowImplBase _baseClass; + + BEGIN_MSG_MAP(CMDIFrameWindowImpl) + MESSAGE_HANDLER(WM_SIZE, OnSize) + MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) + MESSAGE_HANDLER(WM_MDISETMENU, OnMDISetMenu) +#ifndef _ATL_NO_REBAR_SUPPORT +#if (_WIN32_IE >= 0x0400) + NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnReBarAutoSize) +#endif // (_WIN32_IE >= 0x0400) +#if (_WIN32_IE >= 0x0500) + NOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed) +#endif // (_WIN32_IE >= 0x0500) +#endif // !_ATL_NO_REBAR_SUPPORT + CHAIN_MSG_MAP(_baseClass) + END_MSG_MAP() + + LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + if(wParam != SIZE_MINIMIZED) + { + T* pT = static_cast(this); + pT->UpdateLayout(); + } + // message must be handled, otherwise DefFrameProc would resize the client again + return 0; + } + + LRESULT OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + // don't allow CFrameWindowImplBase to handle this one + return DefWindowProc(uMsg, wParam, lParam); + } + + LRESULT OnMDISetMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + SetMDIFrameMenu(); + return 0; + } + +#ifndef _ATL_NO_REBAR_SUPPORT +#if (_WIN32_IE >= 0x0400) + LRESULT OnReBarAutoSize(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->UpdateLayout(FALSE); + return 0; + } +#endif // (_WIN32_IE >= 0x0400) + +#if (_WIN32_IE >= 0x0500) + LRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) + { + T* pT = static_cast(this); + _ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false }; + if(!pT->PrepareChevronMenu(cmi)) + { + bHandled = FALSE; + return 1; + } + // display a popup menu with hidden items + pT->DisplayChevronMenu(cmi); + // cleanup + pT->CleanupChevronMenu(cmi); + return 0; + } +#endif // (_WIN32_IE >= 0x0500) +#endif // !_ATL_NO_REBAR_SUPPORT +}; + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CMDIChildWindowImpl + +#ifndef _WIN32_WCE + +template +class ATL_NO_VTABLE CMDIChildWindowImpl : public CFrameWindowImplBase +{ +public: + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + UINT nMenuID = 0, LPVOID lpCreateParam = NULL) + { + ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc); + + if(nMenuID != 0) + m_hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(nMenuID)); + + dwStyle = T::GetWndStyle(dwStyle); + dwExStyle = T::GetWndExStyle(dwExStyle); + + dwExStyle |= WS_EX_MDICHILD; // force this one + m_pfnSuperWindowProc = ::DefMDIChildProc; + m_hWndMDIClient = hWndParent; + ATLASSERT(::IsWindow(m_hWndMDIClient)); + + if(rect.m_lpRect == NULL) + rect.m_lpRect = &TBase::rcDefault; + + // If the currently active MDI child is maximized, we want to create this one maximized too + ATL::CWindow wndParent = hWndParent; + BOOL bMaximized = FALSE; + wndParent.SendMessage(WM_MDIGETACTIVE, 0, (LPARAM)&bMaximized); + if(bMaximized) + wndParent.SetRedraw(FALSE); + + HWND hWnd = CFrameWindowImplBase::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, (UINT)0U, atom, lpCreateParam); + + if(bMaximized) + { + // Maximize and redraw everything + if(hWnd != NULL) + MDIMaximize(hWnd); + wndParent.SetRedraw(TRUE); + wndParent.RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN); + ::SetFocus(GetMDIFrame()); // focus will be set back to this window + } + else if(hWnd != NULL && ::IsWindowVisible(m_hWnd) && !::IsChild(hWnd, ::GetFocus())) + { + ::SetFocus(hWnd); + } + + return hWnd; + } + + HWND CreateEx(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR lpcstrWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL) + { + const int cchName = 256; + TCHAR szWindowName[cchName]; + szWindowName[0] = 0; + if(lpcstrWindowName == NULL) + { + ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName); + lpcstrWindowName = szWindowName; + } + + T* pT = static_cast(this); + HWND hWnd = pT->Create(hWndParent, rect, lpcstrWindowName, dwStyle, dwExStyle, T::GetWndClassInfo().m_uCommonResourceID, lpCreateParam); + + if(hWnd != NULL) + m_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID)); + + return hWnd; + } + + BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) + { + ATLASSERT(!::IsWindow(m_hWndToolBar)); + if(nResourceID == 0) + nResourceID = T::GetWndClassInfo().m_uCommonResourceID; + m_hWndToolBar = T::CreateSimpleToolBarCtrl(m_hWnd, nResourceID, TRUE, dwStyle, nID); + return (m_hWndToolBar != NULL); + } + + BOOL UpdateClientEdge(LPRECT lpRect = NULL) + { + // only adjust for active MDI child window + HWND hWndChild = MDIGetActive(); + if(hWndChild != NULL && hWndChild != m_hWnd) + return FALSE; + + // need to adjust the client edge style as max/restore happens + DWORD dwStyle = ::GetWindowLong(m_hWndMDIClient, GWL_EXSTYLE); + DWORD dwNewStyle = dwStyle; + if(hWndChild != NULL && ((GetExStyle() & WS_EX_CLIENTEDGE) == 0) && ((GetStyle() & WS_MAXIMIZE) != 0)) + dwNewStyle &= ~(WS_EX_CLIENTEDGE); + else + dwNewStyle |= WS_EX_CLIENTEDGE; + + if(dwStyle != dwNewStyle) + { + // SetWindowPos will not move invalid bits + ::RedrawWindow(m_hWndMDIClient, NULL, NULL, + RDW_INVALIDATE | RDW_ALLCHILDREN); + // remove/add WS_EX_CLIENTEDGE to MDI client area + ::SetWindowLong(m_hWndMDIClient, GWL_EXSTYLE, dwNewStyle); + ::SetWindowPos(m_hWndMDIClient, NULL, 0, 0, 0, 0, + SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | + SWP_NOZORDER | SWP_NOCOPYBITS); + + // return new client area + if (lpRect != NULL) + ::GetClientRect(m_hWndMDIClient, lpRect); + + return TRUE; + } + + return FALSE; + } + + typedef CFrameWindowImplBase _baseClass; + BEGIN_MSG_MAP(CMDIChildWindowImpl) + MESSAGE_HANDLER(WM_SIZE, OnSize) + MESSAGE_HANDLER(WM_WINDOWPOSCHANGED, OnWindowPosChanged) + MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate) + MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect) + MESSAGE_HANDLER(WM_MDIACTIVATE, OnMDIActivate) + MESSAGE_HANDLER(WM_DESTROY, OnDestroy) +#ifndef _ATL_NO_REBAR_SUPPORT +#if (_WIN32_IE >= 0x0400) + NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnReBarAutoSize) +#endif // (_WIN32_IE >= 0x0400) +#if (_WIN32_IE >= 0x0500) + NOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed) +#endif // (_WIN32_IE >= 0x0500) +#endif // !_ATL_NO_REBAR_SUPPORT + CHAIN_MSG_MAP(_baseClass) + END_MSG_MAP() + + LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + DefWindowProc(uMsg, wParam, lParam); // needed for MDI children + if(wParam != SIZE_MINIMIZED) + { + T* pT = static_cast(this); + pT->UpdateLayout(); + } + return 0; + } + + LRESULT OnWindowPosChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + // update MDI client edge and adjust MDI child rect + LPWINDOWPOS lpWndPos = (LPWINDOWPOS)lParam; + + if(!(lpWndPos->flags & SWP_NOSIZE)) + { + RECT rectClient; + if(UpdateClientEdge(&rectClient) && ((GetStyle() & WS_MAXIMIZE) != 0)) + { + ::AdjustWindowRectEx(&rectClient, GetStyle(), FALSE, GetExStyle()); + lpWndPos->x = rectClient.left; + lpWndPos->y = rectClient.top; + lpWndPos->cx = rectClient.right - rectClient.left; + lpWndPos->cy = rectClient.bottom - rectClient.top; + } + } + + bHandled = FALSE; + return 1; + } + + LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + LRESULT lRes = DefWindowProc(uMsg, wParam, lParam); + + // Activate this MDI window if needed + if(lRes == MA_ACTIVATE || lRes == MA_ACTIVATEANDEAT) + { + if(MDIGetActive() != m_hWnd) + MDIActivate(m_hWnd); + } + + return lRes; + } + + LRESULT OnMenuSelect(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + return ::SendMessage(GetMDIFrame(), uMsg, wParam, lParam); + } + + LRESULT OnMDIActivate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + if((HWND)lParam == m_hWnd && m_hMenu != NULL) + SetMDIFrameMenu(); + else if((HWND)lParam == NULL) + ::SendMessage(GetMDIFrame(), WM_MDISETMENU, 0, 0); + + bHandled = FALSE; + return 1; + } + + LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if(m_hMenu != NULL) + { + ::DestroyMenu(m_hMenu); + m_hMenu = NULL; + } + UpdateClientEdge(); + bHandled = FALSE; + return 1; + } + +#ifndef _ATL_NO_REBAR_SUPPORT +#if (_WIN32_IE >= 0x0400) + LRESULT OnReBarAutoSize(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->UpdateLayout(FALSE); + return 0; + } +#endif // (_WIN32_IE >= 0x0400) + +#if (_WIN32_IE >= 0x0500) + LRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) + { + T* pT = static_cast(this); + _ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false }; + if(!pT->PrepareChevronMenu(cmi)) + { + bHandled = FALSE; + return 1; + } + // display a popup menu with hidden items + pT->DisplayChevronMenu(cmi); + // cleanup + pT->CleanupChevronMenu(cmi); + return 0; + } +#endif // (_WIN32_IE >= 0x0500) +#endif // !_ATL_NO_REBAR_SUPPORT +}; + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// COwnerDraw - MI class for owner-draw support + +template +class COwnerDraw +{ +public: +#if (_ATL_VER < 0x0700) + BOOL m_bHandledOD; + + BOOL IsMsgHandled() const + { + return m_bHandledOD; + } + void SetMsgHandled(BOOL bHandled) + { + m_bHandledOD = bHandled; + } +#endif // (_ATL_VER < 0x0700) + +// Message map and handlers + BEGIN_MSG_MAP(COwnerDraw< T >) + MESSAGE_HANDLER(WM_DRAWITEM, OnDrawItem) + MESSAGE_HANDLER(WM_MEASUREITEM, OnMeasureItem) + MESSAGE_HANDLER(WM_COMPAREITEM, OnCompareItem) + MESSAGE_HANDLER(WM_DELETEITEM, OnDeleteItem) + ALT_MSG_MAP(1) + MESSAGE_HANDLER(OCM_DRAWITEM, OnDrawItem) + MESSAGE_HANDLER(OCM_MEASUREITEM, OnMeasureItem) + MESSAGE_HANDLER(OCM_COMPAREITEM, OnCompareItem) + MESSAGE_HANDLER(OCM_DELETEITEM, OnDeleteItem) + END_MSG_MAP() + + LRESULT OnDrawItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + T* pT = static_cast(this); + pT->SetMsgHandled(TRUE); + pT->DrawItem((LPDRAWITEMSTRUCT)lParam); + bHandled = pT->IsMsgHandled(); + return (LRESULT)TRUE; + } + + LRESULT OnMeasureItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + T* pT = static_cast(this); + pT->SetMsgHandled(TRUE); + pT->MeasureItem((LPMEASUREITEMSTRUCT)lParam); + bHandled = pT->IsMsgHandled(); + return (LRESULT)TRUE; + } + + LRESULT OnCompareItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + T* pT = static_cast(this); + pT->SetMsgHandled(TRUE); + bHandled = pT->IsMsgHandled(); + return (LRESULT)pT->CompareItem((LPCOMPAREITEMSTRUCT)lParam); + } + + LRESULT OnDeleteItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + T* pT = static_cast(this); + pT->SetMsgHandled(TRUE); + pT->DeleteItem((LPDELETEITEMSTRUCT)lParam); + bHandled = pT->IsMsgHandled(); + return (LRESULT)TRUE; + } + +// Overrideables + void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/) + { + // must be implemented + ATLASSERT(FALSE); + } + + void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct) + { + if(lpMeasureItemStruct->CtlType != ODT_MENU) + { + // return default height for a system font + T* pT = static_cast(this); + HWND hWnd = pT->GetDlgItem(lpMeasureItemStruct->CtlID); + CClientDC dc(hWnd); + TEXTMETRIC tm = { 0 }; + dc.GetTextMetrics(&tm); + + lpMeasureItemStruct->itemHeight = tm.tmHeight; + } + else + lpMeasureItemStruct->itemHeight = ::GetSystemMetrics(SM_CYMENU); + } + + int CompareItem(LPCOMPAREITEMSTRUCT /*lpCompareItemStruct*/) + { + // all items are equal + return 0; + } + + void DeleteItem(LPDELETEITEMSTRUCT /*lpDeleteItemStruct*/) + { + // default - nothing + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// Update UI macros + +// these build the Update UI map inside a class definition +#define BEGIN_UPDATE_UI_MAP(thisClass) \ + static const CUpdateUIBase::_AtlUpdateUIMap* GetUpdateUIMap() \ + { \ + static const _AtlUpdateUIMap theMap[] = \ + { + +#define UPDATE_ELEMENT(nID, wType) \ + { nID, wType }, + +#define END_UPDATE_UI_MAP() \ + { (WORD)-1, 0 } \ + }; \ + return theMap; \ + } + +/////////////////////////////////////////////////////////////////////////////// +// CUpdateUI - manages UI elements updating + +class CUpdateUIBase +{ +public: + // constants + enum + { + // UI element type + UPDUI_MENUPOPUP = 0x0001, + UPDUI_MENUBAR = 0x0002, + UPDUI_CHILDWINDOW = 0x0004, + UPDUI_TOOLBAR = 0x0008, + UPDUI_STATUSBAR = 0x0010, + // state + UPDUI_ENABLED = 0x0000, + UPDUI_DISABLED = 0x0100, + UPDUI_CHECKED = 0x0200, + UPDUI_CHECKED2 = 0x0400, + UPDUI_RADIO = 0x0800, + UPDUI_DEFAULT = 0x1000, + UPDUI_TEXT = 0x2000, + // internal state + UPDUI_CLEARDEFAULT = 0x4000, + }; + + // element data + struct _AtlUpdateUIElement + { + HWND m_hWnd; + WORD m_wType; + + bool operator ==(const _AtlUpdateUIElement& e) const + { return (m_hWnd == e.m_hWnd && m_wType == e.m_wType); } + }; + + // map data + struct _AtlUpdateUIMap + { + WORD m_nID; + WORD m_wType; + + bool operator ==(const _AtlUpdateUIMap& e) const + { return (m_nID == e.m_nID && m_wType == e.m_wType); } + }; + + // instance data + struct _AtlUpdateUIData + { + WORD m_wState; + union + { + void* m_lpData; + LPTSTR m_lpstrText; + struct + { + WORD m_nIDFirst; + WORD m_nIDLast; + }; + }; + + bool operator ==(const _AtlUpdateUIData& e) const + { return (m_wState == e.m_wState && m_lpData == e.m_lpData); } + }; + + ATL::CSimpleArray<_AtlUpdateUIElement> m_UIElements; // elements data + const _AtlUpdateUIMap* m_pUIMap; // static UI data + _AtlUpdateUIData* m_pUIData; // instance UI data + WORD m_wDirtyType; // global dirty flag + + bool m_bBlockAccelerators; + + +// Constructor, destructor + CUpdateUIBase() : m_pUIMap(NULL), m_pUIData(NULL), m_wDirtyType(0), m_bBlockAccelerators(false) + { } + + ~CUpdateUIBase() + { + if(m_pUIMap != NULL && m_pUIData != NULL) + { + const _AtlUpdateUIMap* pUIMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + while(pUIMap->m_nID != (WORD)-1) + { + if(pUIData->m_wState & UPDUI_TEXT) + delete [] pUIData->m_lpstrText; + pUIMap++; + pUIData++; + } + delete [] m_pUIData; + } + } + +// Check for disabled commands + bool UIGetBlockAccelerators() const + { + return m_bBlockAccelerators; + } + + bool UISetBlockAccelerators(bool bBlock) + { + bool bOld = m_bBlockAccelerators; + m_bBlockAccelerators = bBlock; + return bOld; + } + +// Add elements + BOOL UIAddMenuBar(HWND hWnd) // menu bar (main menu) + { + if(hWnd == NULL) + return FALSE; + _AtlUpdateUIElement e; + e.m_hWnd = hWnd; + e.m_wType = UPDUI_MENUBAR; + return m_UIElements.Add(e); + } + + BOOL UIAddToolBar(HWND hWnd) // toolbar + { + if(hWnd == NULL) + return FALSE; + _AtlUpdateUIElement e; + e.m_hWnd = hWnd; + e.m_wType = UPDUI_TOOLBAR; + return m_UIElements.Add(e); + } + + BOOL UIAddStatusBar(HWND hWnd) // status bar + { + if(hWnd == NULL) + return FALSE; + _AtlUpdateUIElement e; + e.m_hWnd = hWnd; + e.m_wType = UPDUI_STATUSBAR; + return m_UIElements.Add(e); + } + + BOOL UIAddChildWindowContainer(HWND hWnd) // child window + { + if(hWnd == NULL) + return FALSE; + _AtlUpdateUIElement e; + e.m_hWnd = hWnd; + e.m_wType = UPDUI_CHILDWINDOW; + return m_UIElements.Add(e); + } + +// Message map for popup menu updates and accelerator blocking + BEGIN_MSG_MAP(CUpdateUIBase) + MESSAGE_HANDLER(WM_INITMENUPOPUP, OnInitMenuPopup) + MESSAGE_HANDLER(WM_COMMAND, OnCommand) + END_MSG_MAP() + + LRESULT OnInitMenuPopup(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + bHandled = FALSE; + HMENU hMenu = (HMENU)wParam; + if(hMenu == NULL) + return 1; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return 1; + const _AtlUpdateUIMap* pMap = m_pUIMap; + while(pMap->m_nID != (WORD)-1) + { + if(pMap->m_wType & UPDUI_MENUPOPUP) + { + UIUpdateMenuBarElement(pMap->m_nID, pUIData, hMenu); + + if((pUIData->m_wState & UPDUI_RADIO) != 0) + ::CheckMenuRadioItem(hMenu, pUIData->m_nIDFirst, pUIData->m_nIDLast, pMap->m_nID, MF_BYCOMMAND); + } + pMap++; + pUIData++; + } + return 0; + } + + LRESULT OnCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + bHandled = FALSE; + if(m_bBlockAccelerators && HIWORD(wParam) == 1) // accelerators only + { + int nID = LOWORD(wParam); + if((UIGetState(nID) & UPDUI_DISABLED) == UPDUI_DISABLED) + { + ATLTRACE2(atlTraceUI, 0, _T("CUpdateUIBase::OnCommand - blocked disabled command 0x%4.4X\n"), nID); + bHandled = TRUE; // eat the command, UI item is disabled + } + } + return 0; + } + +// methods for setting UI element state + BOOL UIEnable(int nID, BOOL bEnable, BOOL bForceUpdate = FALSE) + { + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return FALSE; + + for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) + { + if(nID == (int)pMap->m_nID) + { + if(bEnable) + { + if(pUIData->m_wState & UPDUI_DISABLED) + { + pUIData->m_wState |= pMap->m_wType; + pUIData->m_wState &= ~UPDUI_DISABLED; + } + } + else + { + if(!(pUIData->m_wState & UPDUI_DISABLED)) + { + pUIData->m_wState |= pMap->m_wType; + pUIData->m_wState |= UPDUI_DISABLED; + } + } + + if(bForceUpdate) + pUIData->m_wState |= pMap->m_wType; + if(pUIData->m_wState & pMap->m_wType) + m_wDirtyType |= pMap->m_wType; + + break; // found + } + } + + return TRUE; + } + + BOOL UISetCheck(int nID, int nCheck, BOOL bForceUpdate = FALSE) + { + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return FALSE; + + for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) + { + if(nID == (int)pMap->m_nID) + { + switch(nCheck) + { + case 0: + if((pUIData->m_wState & UPDUI_CHECKED) || (pUIData->m_wState & UPDUI_CHECKED2)) + { + pUIData->m_wState |= pMap->m_wType; + pUIData->m_wState &= ~(UPDUI_CHECKED | UPDUI_CHECKED2); + } + break; + case 1: + if(!(pUIData->m_wState & UPDUI_CHECKED)) + { + pUIData->m_wState |= pMap->m_wType; + pUIData->m_wState &= ~UPDUI_CHECKED2; + pUIData->m_wState |= UPDUI_CHECKED; + } + break; + case 2: + if(!(pUIData->m_wState & UPDUI_CHECKED2)) + { + pUIData->m_wState |= pMap->m_wType; + pUIData->m_wState &= ~UPDUI_CHECKED; + pUIData->m_wState |= UPDUI_CHECKED2; + } + break; + } + + if(bForceUpdate) + pUIData->m_wState |= pMap->m_wType; + if(pUIData->m_wState & pMap->m_wType) + m_wDirtyType |= pMap->m_wType; + + break; // found + } + } + + return TRUE; + } + + // variant that supports bool (checked/not-checked, no intermediate state) + BOOL UISetCheck(int nID, bool bCheck, BOOL bForceUpdate = FALSE) + { + return UISetCheck(nID, bCheck ? 1 : 0, bForceUpdate); + } + + BOOL UISetRadio(int nID, BOOL bRadio, BOOL bForceUpdate = FALSE) + { + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return FALSE; + + for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) + { + if(nID == (int)pMap->m_nID) + { + if(bRadio) + { + if(!(pUIData->m_wState & UPDUI_RADIO)) + { + pUIData->m_wState |= pMap->m_wType; + pUIData->m_wState |= UPDUI_RADIO; + } + } + else + { + if(pUIData->m_wState & UPDUI_RADIO) + { + pUIData->m_wState |= pMap->m_wType; + pUIData->m_wState &= ~UPDUI_RADIO; + } + } + + if(bForceUpdate) + pUIData->m_wState |= pMap->m_wType; + if(pUIData->m_wState & pMap->m_wType) + m_wDirtyType |= pMap->m_wType; + + break; // found + } + } + + return TRUE; + } + + // for menu items + BOOL UISetRadioMenuItem(int nID, int nIDFirst, int nIDLast, BOOL bForceUpdate = FALSE) + { + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return FALSE; + + for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) + { + if(nID == (int)pMap->m_nID) + { + pUIData->m_wState |= pMap->m_wType; + pUIData->m_wState |= UPDUI_RADIO; + pUIData->m_nIDFirst = (WORD)nIDFirst; + pUIData->m_nIDLast = (WORD)nIDLast; + + if(bForceUpdate) + pUIData->m_wState |= pMap->m_wType; + if(pUIData->m_wState & pMap->m_wType) + m_wDirtyType |= pMap->m_wType; + } + else if(pMap->m_nID >= nIDFirst && pMap->m_nID <= nIDLast) + { + if(pUIData->m_wState & UPDUI_RADIO) + { + pUIData->m_wState &= ~pMap->m_wType; + pUIData->m_wState &= ~UPDUI_RADIO; + pUIData->m_nIDFirst = 0; + pUIData->m_nIDLast = 0; + } + } + + if(pMap->m_nID == nIDLast) + break; + } + + return TRUE; + } + + BOOL UISetText(int nID, LPCTSTR lpstrText, BOOL bForceUpdate = FALSE) + { + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return FALSE; + if(lpstrText == NULL) + lpstrText = _T(""); + + for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) + { + if(nID == (int)pMap->m_nID) + { + if(pUIData->m_lpstrText == NULL || lstrcmp(pUIData->m_lpstrText, lpstrText)) + { + delete [] pUIData->m_lpstrText; + pUIData->m_lpstrText = NULL; + int nStrLen = lstrlen(lpstrText); + ATLTRY(pUIData->m_lpstrText = new TCHAR[nStrLen + 1]); + if(pUIData->m_lpstrText == NULL) + { + ATLTRACE2(atlTraceUI, 0, _T("UISetText - memory allocation failed\n")); + break; + } + SecureHelper::strcpy_x(pUIData->m_lpstrText, nStrLen + 1, lpstrText); + pUIData->m_wState |= (UPDUI_TEXT | pMap->m_wType); + } + + if(bForceUpdate) + pUIData->m_wState |= (UPDUI_TEXT | pMap->m_wType); + if(pUIData->m_wState & pMap->m_wType) + m_wDirtyType |= pMap->m_wType; + + break; // found + } + } + + return TRUE; + } + + BOOL UISetDefault(int nID, BOOL bDefault, BOOL bForceUpdate = FALSE) + { + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return FALSE; + + for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) + { + if(nID == (int)pMap->m_nID) + { + if(bDefault) + { + if((pUIData->m_wState & UPDUI_DEFAULT) == 0) + { + pUIData->m_wState |= pMap->m_wType; + pUIData->m_wState |= UPDUI_DEFAULT; + } + } + else + { + if((pUIData->m_wState & UPDUI_DEFAULT) != 0) + { + pUIData->m_wState |= pMap->m_wType; + pUIData->m_wState &= ~UPDUI_DEFAULT; + pUIData->m_wState |= UPDUI_CLEARDEFAULT; + } + } + + if(bForceUpdate) + pUIData->m_wState |= pMap->m_wType; + if(pUIData->m_wState & pMap->m_wType) + m_wDirtyType |= pMap->m_wType; + + break; // found + } + } + + return TRUE; + } + +// methods for complete state set/get + BOOL UISetState(int nID, DWORD dwState) + { + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return FALSE; + for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) + { + if(nID == (int)pMap->m_nID) + { + pUIData->m_wState = (WORD)(dwState | pMap->m_wType); + m_wDirtyType |= pMap->m_wType; + break; // found + } + } + return TRUE; + } + + DWORD UIGetState(int nID) + { + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return 0; + for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) + { + if(nID == (int)pMap->m_nID) + return pUIData->m_wState; + } + return 0; + } + +// methods for updating UI +#ifndef _WIN32_WCE + BOOL UIUpdateMenuBar(BOOL bForceUpdate = FALSE, BOOL bMainMenu = FALSE) + { + if(!(m_wDirtyType & UPDUI_MENUBAR) && !bForceUpdate) + return TRUE; + + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return FALSE; + + while(pMap->m_nID != (WORD)-1) + { + for(int i = 0; i < m_UIElements.GetSize(); i++) + { + if(m_UIElements[i].m_wType == UPDUI_MENUBAR) + { + HMENU hMenu = ::GetMenu(m_UIElements[i].m_hWnd); + if(hMenu != NULL && (pUIData->m_wState & UPDUI_MENUBAR) && (pMap->m_wType & UPDUI_MENUBAR)) + UIUpdateMenuBarElement(pMap->m_nID, pUIData, hMenu); + } + if(bMainMenu) + ::DrawMenuBar(m_UIElements[i].m_hWnd); + } + pMap++; + pUIData->m_wState &= ~UPDUI_MENUBAR; + if(pUIData->m_wState & UPDUI_TEXT) + { + delete [] pUIData->m_lpstrText; + pUIData->m_lpstrText = NULL; + pUIData->m_wState &= ~UPDUI_TEXT; + } + pUIData++; + } + + m_wDirtyType &= ~UPDUI_MENUBAR; + return TRUE; + } +#endif // !_WIN32_WCE + + BOOL UIUpdateToolBar(BOOL bForceUpdate = FALSE) + { + if(!(m_wDirtyType & UPDUI_TOOLBAR) && !bForceUpdate) + return TRUE; + + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return FALSE; + + while(pMap->m_nID != (WORD)-1) + { + for(int i = 0; i < m_UIElements.GetSize(); i++) + { + if(m_UIElements[i].m_wType == UPDUI_TOOLBAR) + { + if((pUIData->m_wState & UPDUI_TOOLBAR) && (pMap->m_wType & UPDUI_TOOLBAR)) + UIUpdateToolBarElement(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd); + } + } + pMap++; + pUIData->m_wState &= ~UPDUI_TOOLBAR; + pUIData++; + } + + m_wDirtyType &= ~UPDUI_TOOLBAR; + return TRUE; + } + + BOOL UIUpdateStatusBar(BOOL bForceUpdate = FALSE) + { + if(!(m_wDirtyType & UPDUI_STATUSBAR) && !bForceUpdate) + return TRUE; + + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return FALSE; + + while(pMap->m_nID != (WORD)-1) + { + for(int i = 0; i < m_UIElements.GetSize(); i++) + { + if(m_UIElements[i].m_wType == UPDUI_STATUSBAR) + { + if((pUIData->m_wState & UPDUI_STATUSBAR) && (pMap->m_wType & UPDUI_STATUSBAR)) + UIUpdateStatusBarElement(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd); + } + } + pMap++; + pUIData->m_wState &= ~UPDUI_STATUSBAR; + if(pUIData->m_wState & UPDUI_TEXT) + { + delete [] pUIData->m_lpstrText; + pUIData->m_lpstrText = NULL; + pUIData->m_wState &= ~UPDUI_TEXT; + } + pUIData++; + } + + m_wDirtyType &= ~UPDUI_STATUSBAR; + return TRUE; + } + + BOOL UIUpdateChildWindows(BOOL bForceUpdate = FALSE) + { + if(!(m_wDirtyType & UPDUI_CHILDWINDOW) && !bForceUpdate) + return TRUE; + + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return FALSE; + + while(pMap->m_nID != (WORD)-1) + { + for(int i = 0; i < m_UIElements.GetSize(); i++) + { + if(m_UIElements[i].m_wType == UPDUI_CHILDWINDOW) + { + if((pUIData->m_wState & UPDUI_CHILDWINDOW) && (pMap->m_wType & UPDUI_CHILDWINDOW)) + UIUpdateChildWindow(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd); + } + } + pMap++; + pUIData->m_wState &= ~UPDUI_CHILDWINDOW; + if(pUIData->m_wState & UPDUI_TEXT) + { + delete [] pUIData->m_lpstrText; + pUIData->m_lpstrText = NULL; + pUIData->m_wState &= ~UPDUI_TEXT; + } + pUIData++; + } + + m_wDirtyType &= ~UPDUI_CHILDWINDOW; + return TRUE; + } + +// internal element specific methods + static void UIUpdateMenuBarElement(int nID, _AtlUpdateUIData* pUIData, HMENU hMenu) + { +#ifndef _WIN32_WCE + if((pUIData->m_wState & UPDUI_CLEARDEFAULT) != 0) + { + ::SetMenuDefaultItem(hMenu, (UINT)-1, 0); + pUIData->m_wState &= ~UPDUI_CLEARDEFAULT; + } +#endif // !_WIN32_WCE + + CMenuItemInfo mii; + mii.fMask = MIIM_STATE; + mii.wID = nID; + +#ifndef _WIN32_WCE + if((pUIData->m_wState & UPDUI_DISABLED) != 0) + mii.fState |= MFS_DISABLED | MFS_GRAYED; + else + mii.fState |= MFS_ENABLED; + + if((pUIData->m_wState & UPDUI_CHECKED) != 0) + mii.fState |= MFS_CHECKED; + else + mii.fState |= MFS_UNCHECKED; + + if((pUIData->m_wState & UPDUI_DEFAULT) != 0) + mii.fState |= MFS_DEFAULT; +#else // CE specific + // ::SetMenuItemInfo() can't disable or check menu items + // on Windows CE, so we have to do that directly + UINT uEnable = MF_BYCOMMAND; + if((pUIData->m_wState & UPDUI_DISABLED) != 0) + uEnable |= MF_GRAYED; + else + uEnable |= MF_ENABLED; + ::EnableMenuItem(hMenu, nID, uEnable); + + UINT uCheck = MF_BYCOMMAND; + if((pUIData->m_wState & UPDUI_CHECKED) != 0) + uCheck |= MF_CHECKED; + else + uCheck |= MF_UNCHECKED; + ::CheckMenuItem(hMenu, nID, uCheck); +#endif // _WIN32_WCE + + if((pUIData->m_wState & UPDUI_TEXT) != 0) + { + CMenuItemInfo miiNow; + miiNow.fMask = MIIM_TYPE; + miiNow.wID = nID; + if(::GetMenuItemInfo(hMenu, nID, FALSE, &miiNow)) + { + mii.fMask |= MIIM_TYPE; + // MFT_BITMAP and MFT_SEPARATOR don't go together with MFT_STRING +#ifndef _WIN32_WCE + mii.fType |= (miiNow.fType & ~(MFT_BITMAP | MFT_SEPARATOR)) | MFT_STRING; +#else // CE specific + mii.fType |= (miiNow.fType & ~(MFT_SEPARATOR)) | MFT_STRING; +#endif // _WIN32_WCE + mii.dwTypeData = pUIData->m_lpstrText; + } + } + + ::SetMenuItemInfo(hMenu, nID, FALSE, &mii); + } + + static void UIUpdateToolBarElement(int nID, _AtlUpdateUIData* pUIData, HWND hWndToolBar) + { + // Note: only handles enabled/disabled, checked state, and radio (press) + ::SendMessage(hWndToolBar, TB_ENABLEBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_DISABLED) ? FALSE : TRUE); + ::SendMessage(hWndToolBar, TB_CHECKBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_CHECKED) ? TRUE : FALSE); + ::SendMessage(hWndToolBar, TB_INDETERMINATE, nID, (LPARAM)(pUIData->m_wState & UPDUI_CHECKED2) ? TRUE : FALSE); + ::SendMessage(hWndToolBar, TB_PRESSBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_RADIO) ? TRUE : FALSE); + } + + static void UIUpdateStatusBarElement(int nID, _AtlUpdateUIData* pUIData, HWND hWndStatusBar) + { + // Note: only handles text + if(pUIData->m_wState & UPDUI_TEXT) + ::SendMessage(hWndStatusBar, SB_SETTEXT, nID, (LPARAM)pUIData->m_lpstrText); + } + + static void UIUpdateChildWindow(int nID, _AtlUpdateUIData* pUIData, HWND hWnd) + { + HWND hChild = ::GetDlgItem(hWnd, nID); + + ::EnableWindow(hChild, (pUIData->m_wState & UPDUI_DISABLED) ? FALSE : TRUE); + // for check and radio, assume that window is a button + int nCheck = BST_UNCHECKED; + if(pUIData->m_wState & UPDUI_CHECKED || pUIData->m_wState & UPDUI_RADIO) + nCheck = BST_CHECKED; + else if(pUIData->m_wState & UPDUI_CHECKED2) + nCheck = BST_INDETERMINATE; + ::SendMessage(hChild, BM_SETCHECK, nCheck, 0L); + if(pUIData->m_wState & UPDUI_DEFAULT) + { + DWORD dwRet = (DWORD)::SendMessage(hWnd, DM_GETDEFID, 0, 0L); + if(HIWORD(dwRet) == DC_HASDEFID) + { + HWND hOldDef = ::GetDlgItem(hWnd, (int)(short)LOWORD(dwRet)); + // remove BS_DEFPUSHBUTTON + ::SendMessage(hOldDef, BM_SETSTYLE, BS_PUSHBUTTON, MAKELPARAM(TRUE, 0)); + } + ::SendMessage(hWnd, DM_SETDEFID, nID, 0L); + } + if(pUIData->m_wState & UPDUI_TEXT) + ::SetWindowText(hChild, pUIData->m_lpstrText); + } +}; + +template +class CUpdateUI : public CUpdateUIBase +{ +public: + CUpdateUI() + { + T* pT = static_cast(this); + pT; + const _AtlUpdateUIMap* pMap = pT->GetUpdateUIMap(); + m_pUIMap = pMap; + ATLASSERT(m_pUIMap != NULL); + int nCount; + for(nCount = 1; pMap->m_nID != (WORD)-1; nCount++) + pMap++; + + // check for duplicates (debug only) +#ifdef _DEBUG + for(int i = 0; i < nCount; i++) + { + for(int j = 0; j < nCount; j++) + { + // shouldn't have duplicates in the update UI map + if(i != j) + ATLASSERT(m_pUIMap[j].m_nID != m_pUIMap[i].m_nID); + } + } +#endif // _DEBUG + + ATLTRY(m_pUIData = new _AtlUpdateUIData[nCount]); + ATLASSERT(m_pUIData != NULL); + + if(m_pUIData != NULL) + memset(m_pUIData, 0, sizeof(_AtlUpdateUIData) * nCount); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CDynamicUpdateUI - allows update elements to dynamically added and removed +// in addition to a static update UI map + +template +class CDynamicUpdateUI : public CUpdateUIBase +{ +public: +// Data members + ATL::CSimpleArray<_AtlUpdateUIMap> m_arrUIMap; // copy of the static UI data + ATL::CSimpleArray<_AtlUpdateUIData> m_arrUIData; // instance UI data + +// Constructor/destructor + CDynamicUpdateUI() + { + T* pT = static_cast(this); + pT; + const _AtlUpdateUIMap* pMap = pT->GetUpdateUIMap(); + ATLASSERT(pMap != NULL); + + for(;;) + { + BOOL bRet = m_arrUIMap.Add(*(_AtlUpdateUIMap*)pMap); + ATLASSERT(bRet); + + if(bRet != FALSE) + { + _AtlUpdateUIData data = { 0, NULL }; + bRet = m_arrUIData.Add(data); + ATLASSERT(bRet); + } + + if(pMap->m_nID == (WORD)-1) + break; + + pMap++; + } + + ATLASSERT(m_arrUIMap.GetSize() == m_arrUIData.GetSize()); + +#ifdef _DEBUG + // check for duplicates (debug only) + for(int i = 0; i < m_arrUIMap.GetSize(); i++) + { + for(int j = 0; j < m_arrUIMap.GetSize(); j++) + { + // shouldn't have duplicates in the update UI map + if(i != j) + ATLASSERT(m_arrUIMap[j].m_nID != m_arrUIMap[i].m_nID); + } + } +#endif // _DEBUG + + // Set internal data pointers to point to the new data arrays + m_pUIMap = m_arrUIMap.m_aT; + m_pUIData = m_arrUIData.m_aT; + } + + ~CDynamicUpdateUI() + { + for(int i = 0; i < m_arrUIData.GetSize(); i++) + { + if((m_arrUIData[i].m_wState & UPDUI_TEXT) != 0) + delete [] m_arrUIData[i].m_lpstrText; + } + + // Reset internal data pointers (memory will be released by CSimpleArray d-tor) + m_pUIMap = NULL; + m_pUIData = NULL; + } + +// Methods for dynamically adding and removing update elements + bool UIAddUpdateElement(WORD nID, WORD wType) + { + // check for duplicates + for(int i = 0; i < m_arrUIMap.GetSize(); i++) + { + // shouldn't have duplicates in the update UI map + ATLASSERT(m_arrUIMap[i].m_nID != nID); + if(m_arrUIMap[i].m_nID == nID) + return false; + } + + bool bRetVal = false; + + // Add new end element + _AtlUpdateUIMap uumEnd = { (WORD)-1, 0 }; + BOOL bRet = m_arrUIMap.Add(uumEnd); + ATLASSERT(bRet); + + if(bRet != FALSE) + { + _AtlUpdateUIData uud = { 0, NULL }; + bRet = m_arrUIData.Add(uud); + ATLASSERT(bRet); + + // Set new data to the previous end element + if(bRet != FALSE) + { + int nSize = m_arrUIMap.GetSize(); + _AtlUpdateUIMap uum = { nID, wType }; + m_arrUIMap.SetAtIndex(nSize - 2, uum); + m_arrUIData.SetAtIndex(nSize - 2, uud); + + // Set internal data pointers again, just in case that memory moved + m_pUIMap = m_arrUIMap.m_aT; + m_pUIData = m_arrUIData.m_aT; + + bRetVal = true; + } + } + + return bRetVal; + } + + bool UIRemoveUpdateElement(WORD nID) + { + bool bRetVal = false; + + for(int i = 0; i < m_arrUIMap.GetSize(); i++) + { + if(m_arrUIMap[i].m_nID == nID) + { + BOOL bRet = m_arrUIMap.RemoveAt(i); + ATLASSERT(bRet); + bRet = m_arrUIData.RemoveAt(i); + ATLASSERT(bRet); + + bRetVal = true; + break; + } + } + + return bRetVal; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CAutoUpdateUI : Automatic mapping of UI elements + +template +class CAutoUpdateUI : public CDynamicUpdateUI +{ +public: + LPCTSTR UIGetText(int nID) + { + for(int i = 0; i < m_arrUIMap.GetSize(); i++) + { + if(m_arrUIMap[i].m_nID == nID) + return m_arrUIData[i].m_lpstrText; + } + + return NULL; + } + +// Element + template + bool UIAddElement(UINT nID) + { + // check for existing UI map element + for(int i = 0; i < m_arrUIMap.GetSize(); i++) + { + if(m_arrUIMap[i].m_nID == nID) + { + // set requested type + m_arrUIMap[i].m_wType |= t_wType; + return true; + } + } + + // Add element to UI map with requested type + return UIAddUpdateElement((WORD)nID, t_wType); + } + + template + bool UIRemoveElement(UINT nID) + { + for(int i = 0; i < m_arrUIMap.GetSize(); i++) + { + if(m_arrUIMap[i].m_nID == nID) // matching UI map element + { + WORD wType = m_arrUIMap[i].m_wType & ~t_wType; + if (wType) // has other types + { + m_arrUIMap[i].m_wType = wType; // keep other types + return true; + } + else + { + return UIRemoveUpdateElement((WORD)nID); + } + } + } + + return false; + } + +// Menu + bool UIAddMenu(HMENU hMenu, bool bSetText = false) + { +#if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800) + using ATL::GetMenuString; +#endif + ATLASSERT(::IsMenu(hMenu)); + MENUITEMINFO mii = {sizeof(MENUITEMINFO), MIIM_TYPE | MIIM_ID | MIIM_SUBMENU}; + + // Complete the UI map + for (INT uItem = 0; CMenuHandle(hMenu).GetMenuItemInfo(uItem, TRUE, &mii); uItem++) + { + if(mii.hSubMenu) + { + // Add submenu to UI map + UIAddMenu(mii.hSubMenu, bSetText); + } + else if (mii.wID) + { + // Add element to UI map + UIAddElement(mii.wID); +#if !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800) + if (bSetText) + { + TCHAR sText[64] = { 0 }; + if (GetMenuString(hMenu, uItem, sText, 64, MF_BYPOSITION)) + UISetText(mii.wID, sText); + } +#else + bSetText; +#endif // !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800) + } + } + + return true; + } + + bool UIAddMenu(UINT uID, bool bSetText = false) + { + CMenu menu; + ATLVERIFY(menu.LoadMenu(uID)); + return UIAddMenu(menu, bSetText); + } + +// ToolBar +#ifndef BTNS_SEP + #define BTNS_SEP TBSTYLE_SEP +#endif // BTNS_SEP compatibility + +#if !defined(_WIN32_WCE) || (defined(_AUTOUI_CE_TOOLBAR) && defined(TBIF_BYINDEX)) + bool UIAddToolBar(HWND hWndToolBar) + { + ATLASSERT(::IsWindow(hWndToolBar)); + TBBUTTONINFO tbbi = {sizeof TBBUTTONINFO, TBIF_COMMAND | TBIF_STYLE | TBIF_BYINDEX}; + + // Add toolbar buttons + for (int uItem = 0; ::SendMessage(hWndToolBar, TB_GETBUTTONINFO, uItem, (LPARAM)&tbbi) != -1; uItem++) + { + if (tbbi.fsStyle ^ BTNS_SEP) + UIAddElement(tbbi.idCommand); + } + + // Add embedded controls if any + if (::GetWindow(hWndToolBar, GW_CHILD)) + UIAddChildWindowContainer(hWndToolBar); + + return (CUpdateUIBase::UIAddToolBar(hWndToolBar) != FALSE); + } +#endif // !defined(_WIN32_WCE) || (defined(_AUTOUI_CE_TOOLBAR) && defined(TBIF_BYINDEX)) + +// Container + bool UIAddChildWindowContainer(HWND hWnd) + { + ATLASSERT(::IsWindow(hWnd)); + + // Add children controls if any + for (ATL::CWindow wCtl = ::GetWindow(hWnd, GW_CHILD); wCtl.IsWindow(); wCtl = wCtl.GetWindow(GW_HWNDNEXT)) + { + if (int id = wCtl.GetDlgCtrlID()) + UIAddElement(id); + } + + return (CUpdateUIBase::UIAddChildWindowContainer(hWnd) != FALSE); + } + +// StatusBar + BOOL UIUpdateStatusBar(BOOL bForceUpdate = FALSE) + { + if(!(m_wDirtyType & UPDUI_STATUSBAR) && !bForceUpdate) + return TRUE; + + for(int i = 0; i < m_arrUIMap.GetSize(); i++) + { + for(int e = 0; e < m_UIElements.GetSize(); e++) + { + if((m_UIElements[e].m_wType == UPDUI_STATUSBAR) && + (m_arrUIMap[i].m_wType & UPDUI_STATUSBAR) && + (m_arrUIData[i].m_wState & UPDUI_STATUSBAR)) + { + UIUpdateStatusBarElement(m_arrUIMap[i].m_nID, &m_arrUIData[i], m_UIElements[e].m_hWnd); + m_arrUIData[i].m_wState &= ~UPDUI_STATUSBAR; + if(m_arrUIData[i].m_wState & UPDUI_TEXT) + m_arrUIData[i].m_wState &= ~UPDUI_TEXT; + } + } + } + + m_wDirtyType &= ~UPDUI_STATUSBAR; + return TRUE; + } + + bool UIAddStatusBar(HWND hWndStatusBar, INT nPanes = 1) + { + ATLASSERT(::IsWindow(hWndStatusBar)); + + // Add StatusBar panes + for (int iPane = 0; iPane < nPanes; iPane++) + UIAddElement(ID_DEFAULT_PANE + iPane); + + return (CUpdateUIBase::UIAddStatusBar(hWndStatusBar) != FALSE); + } + +// UI Map used if derived class has none + BEGIN_UPDATE_UI_MAP(CAutoUpdateUI) + END_UPDATE_UI_MAP() +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CDialogResize - provides support for resizing dialog controls +// (works for any window that has child controls) + +// Put CDialogResize in the list of base classes for a dialog (or even plain window), +// then implement DLGRESIZE map by specifying controls and groups of control +// and using DLSZ_* values to specify how are they supposed to be resized. +// +// Notes: +// - Resizeable border (WS_THICKFRAME style) should be set in the dialog template +// for top level dialogs (popup or overlapped), so that users can resize the dialog. +// - Some flags cannot be combined; for instance DLSZ_CENTER_X overrides DLSZ_SIZE_X, +// DLSZ_SIZE_X overrides DLSZ_MOVE_X. X and Y flags can be combined. +// - Order of controls is important - group controls are resized and moved based +// on the position of the previous control in a group. + +// dialog resize map macros +#define BEGIN_DLGRESIZE_MAP(thisClass) \ + static const _AtlDlgResizeMap* GetDlgResizeMap() \ + { \ + static const _AtlDlgResizeMap theMap[] = \ + { + +#define END_DLGRESIZE_MAP() \ + { -1, 0 }, \ + }; \ + return theMap; \ + } + +#define DLGRESIZE_CONTROL(id, flags) \ + { id, flags }, + +#define BEGIN_DLGRESIZE_GROUP() \ + { -1, _DLSZ_BEGIN_GROUP }, + +#define END_DLGRESIZE_GROUP() \ + { -1, _DLSZ_END_GROUP }, + + +template +class CDialogResize +{ +public: +// Data declarations and members + enum + { + DLSZ_SIZE_X = 0x00000001, + DLSZ_SIZE_Y = 0x00000002, + DLSZ_MOVE_X = 0x00000004, + DLSZ_MOVE_Y = 0x00000008, + DLSZ_REPAINT = 0x00000010, + DLSZ_CENTER_X = 0x00000020, + DLSZ_CENTER_Y = 0x00000040, + + // internal use only + _DLSZ_BEGIN_GROUP = 0x00001000, + _DLSZ_END_GROUP = 0x00002000, + _DLSZ_GRIPPER = 0x00004000 + }; + + struct _AtlDlgResizeMap + { + int m_nCtlID; + DWORD m_dwResizeFlags; + }; + + struct _AtlDlgResizeData + { + int m_nCtlID; + DWORD m_dwResizeFlags; + RECT m_rect; + + int GetGroupCount() const + { + return (int)LOBYTE(HIWORD(m_dwResizeFlags)); + } + + void SetGroupCount(int nCount) + { + ATLASSERT(nCount > 0 && nCount < 256); + DWORD dwCount = (DWORD)MAKELONG(0, MAKEWORD(nCount, 0)); + m_dwResizeFlags &= 0xFF00FFFF; + m_dwResizeFlags |= dwCount; + } + + bool operator ==(const _AtlDlgResizeData& r) const + { return (m_nCtlID == r.m_nCtlID && m_dwResizeFlags == r.m_dwResizeFlags); } + }; + + ATL::CSimpleArray<_AtlDlgResizeData> m_arrData; + SIZE m_sizeDialog; + POINT m_ptMinTrackSize; + bool m_bGripper; + + +// Constructor + CDialogResize() : m_bGripper(false) + { + m_sizeDialog.cx = 0; + m_sizeDialog.cy = 0; + m_ptMinTrackSize.x = -1; + m_ptMinTrackSize.y = -1; + } + +// Operations + void DlgResize_Init(bool bAddGripper = true, bool bUseMinTrackSize = true, DWORD dwForceStyle = WS_CLIPCHILDREN) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + + DWORD dwStyle = pT->GetStyle(); + +#ifdef _DEBUG + // Debug only: Check if top level dialogs have a resizeable border. + if(((dwStyle & WS_CHILD) == 0) && ((dwStyle & WS_THICKFRAME) == 0)) + ATLTRACE2(atlTraceUI, 0, _T("DlgResize_Init - warning: top level dialog without the WS_THICKFRAME style - user cannot resize it\n")); +#endif // _DEBUG + + // Force specified styles (default WS_CLIPCHILDREN reduces flicker) + if((dwStyle & dwForceStyle) != dwForceStyle) + pT->ModifyStyle(0, dwForceStyle); + + // Adding this style removes an empty icon that dialogs with WS_THICKFRAME have. + // Setting icon to NULL is required when XP themes are active. + // Note: This will not prevent adding an icon for the dialog using SetIcon() + if((dwStyle & WS_CHILD) == 0) + { + pT->ModifyStyleEx(0, WS_EX_DLGMODALFRAME); + if(pT->GetIcon(FALSE) == NULL) + pT->SetIcon(NULL, FALSE); + } + + // Cleanup in case of multiple initialization + // block: first check for the gripper control, destroy it if needed + { + ATL::CWindow wndGripper = pT->GetDlgItem(ATL_IDW_STATUS_BAR); + if(wndGripper.IsWindow() && m_arrData.GetSize() > 0 && (m_arrData[0].m_dwResizeFlags & _DLSZ_GRIPPER) != 0) + wndGripper.DestroyWindow(); + } + // clear out everything else + m_arrData.RemoveAll(); + m_sizeDialog.cx = 0; + m_sizeDialog.cy = 0; + m_ptMinTrackSize.x = -1; + m_ptMinTrackSize.y = -1; + + // Get initial dialog client size + RECT rectDlg = { 0 }; + pT->GetClientRect(&rectDlg); + m_sizeDialog.cx = rectDlg.right; + m_sizeDialog.cy = rectDlg.bottom; + +#ifndef _WIN32_WCE + // Create gripper if requested + m_bGripper = false; + if(bAddGripper) + { + // shouldn't exist already + ATLASSERT(!::IsWindow(pT->GetDlgItem(ATL_IDW_STATUS_BAR))); + if(!::IsWindow(pT->GetDlgItem(ATL_IDW_STATUS_BAR))) + { + ATL::CWindow wndGripper; + wndGripper.Create(_T("SCROLLBAR"), pT->m_hWnd, rectDlg, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | SBS_SIZEBOX | SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN, 0, ATL_IDW_STATUS_BAR); + ATLASSERT(wndGripper.IsWindow()); + if(wndGripper.IsWindow()) + { + m_bGripper = true; + RECT rectCtl = { 0 }; + wndGripper.GetWindowRect(&rectCtl); + ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rectCtl, 2); + _AtlDlgResizeData data = { ATL_IDW_STATUS_BAR, DLSZ_MOVE_X | DLSZ_MOVE_Y | DLSZ_REPAINT | _DLSZ_GRIPPER, { rectCtl.left, rectCtl.top, rectCtl.right, rectCtl.bottom } }; + m_arrData.Add(data); + } + } + } +#else // CE specific + bAddGripper; // avoid level 4 warning +#endif // _WIN32_WCE + + // Get min track position if requested + if(bUseMinTrackSize) + { + if((dwStyle & WS_CHILD) != 0) + { + RECT rect = { 0 }; + pT->GetClientRect(&rect); + m_ptMinTrackSize.x = rect.right - rect.left; + m_ptMinTrackSize.y = rect.bottom - rect.top; + } + else + { + RECT rect = { 0 }; + pT->GetWindowRect(&rect); + m_ptMinTrackSize.x = rect.right - rect.left; + m_ptMinTrackSize.y = rect.bottom - rect.top; + } + } + + // Walk the map and initialize data + const _AtlDlgResizeMap* pMap = pT->GetDlgResizeMap(); + ATLASSERT(pMap != NULL); + int nGroupStart = -1; + for(int nCount = 1; !(pMap->m_nCtlID == -1 && pMap->m_dwResizeFlags == 0); nCount++, pMap++) + { + if(pMap->m_nCtlID == -1) + { + switch(pMap->m_dwResizeFlags) + { + case _DLSZ_BEGIN_GROUP: + ATLASSERT(nGroupStart == -1); + nGroupStart = m_arrData.GetSize(); + break; + case _DLSZ_END_GROUP: + { + ATLASSERT(nGroupStart != -1); + int nGroupCount = m_arrData.GetSize() - nGroupStart; + m_arrData[nGroupStart].SetGroupCount(nGroupCount); + nGroupStart = -1; + } + break; + default: + ATLASSERT(FALSE && _T("Invalid DLGRESIZE Map Entry")); + break; + } + } + else + { + // this ID conflicts with the default gripper one + ATLASSERT(m_bGripper ? (pMap->m_nCtlID != ATL_IDW_STATUS_BAR) : TRUE); + + ATL::CWindow ctl = pT->GetDlgItem(pMap->m_nCtlID); + ATLASSERT(ctl.IsWindow()); + RECT rectCtl = { 0 }; + ctl.GetWindowRect(&rectCtl); + ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rectCtl, 2); + + DWORD dwGroupFlag = (nGroupStart != -1 && m_arrData.GetSize() == nGroupStart) ? _DLSZ_BEGIN_GROUP : 0; + _AtlDlgResizeData data = { pMap->m_nCtlID, pMap->m_dwResizeFlags | dwGroupFlag, { rectCtl.left, rectCtl.top, rectCtl.right, rectCtl.bottom } }; + m_arrData.Add(data); + } + } + ATLASSERT((nGroupStart == -1) && _T("No End Group Entry in the DLGRESIZE Map")); + } + + void DlgResize_UpdateLayout(int cxWidth, int cyHeight) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + + // Restrict minimum size if requested + if(((pT->GetStyle() & WS_CHILD) != 0) && m_ptMinTrackSize.x != -1 && m_ptMinTrackSize.y != -1) + { + if(cxWidth < m_ptMinTrackSize.x) + cxWidth = m_ptMinTrackSize.x; + if(cyHeight < m_ptMinTrackSize.y) + cyHeight = m_ptMinTrackSize.y; + } + + BOOL bVisible = pT->IsWindowVisible(); + if(bVisible) + pT->SetRedraw(FALSE); + + for(int i = 0; i < m_arrData.GetSize(); i++) + { + if((m_arrData[i].m_dwResizeFlags & _DLSZ_BEGIN_GROUP) != 0) // start of a group + { + int nGroupCount = m_arrData[i].GetGroupCount(); + ATLASSERT(nGroupCount > 0 && i + nGroupCount - 1 < m_arrData.GetSize()); + RECT rectGroup = m_arrData[i].m_rect; + + int j = 1; + for(j = 1; j < nGroupCount; j++) + { + rectGroup.left = min(rectGroup.left, m_arrData[i + j].m_rect.left); + rectGroup.top = min(rectGroup.top, m_arrData[i + j].m_rect.top); + rectGroup.right = max(rectGroup.right, m_arrData[i + j].m_rect.right); + rectGroup.bottom = max(rectGroup.bottom, m_arrData[i + j].m_rect.bottom); + } + + for(j = 0; j < nGroupCount; j++) + { + _AtlDlgResizeData* pDataPrev = NULL; + if(j > 0) + pDataPrev = &(m_arrData[i + j - 1]); + pT->DlgResize_PositionControl(cxWidth, cyHeight, rectGroup, m_arrData[i + j], true, pDataPrev); + } + + i += nGroupCount - 1; // increment to skip all group controls + } + else // one control entry + { + RECT rectGroup = { 0, 0, 0, 0 }; + pT->DlgResize_PositionControl(cxWidth, cyHeight, rectGroup, m_arrData[i], false); + } + } + + if(bVisible) + pT->SetRedraw(TRUE); + + pT->RedrawWindow(NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); + } + +// Message map and handlers + BEGIN_MSG_MAP(CDialogResize) + MESSAGE_HANDLER(WM_SIZE, OnSize) +#ifndef _WIN32_WCE + MESSAGE_HANDLER(WM_GETMINMAXINFO, OnGetMinMaxInfo) +#endif // _WIN32_WCE + END_MSG_MAP() + + LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); +#ifndef _WIN32_WCE + if(m_bGripper) + { + ATL::CWindow wndGripper = pT->GetDlgItem(ATL_IDW_STATUS_BAR); + if(wParam == SIZE_MAXIMIZED) + wndGripper.ShowWindow(SW_HIDE); + else if(wParam == SIZE_RESTORED) + wndGripper.ShowWindow(SW_SHOW); + } +#endif // _WIN32_WCE + if(wParam != SIZE_MINIMIZED) + { + ATLASSERT(::IsWindow(pT->m_hWnd)); + pT->DlgResize_UpdateLayout(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + } + return 0; + } + +#ifndef _WIN32_WCE + LRESULT OnGetMinMaxInfo(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) + { + if(m_ptMinTrackSize.x != -1 && m_ptMinTrackSize.y != -1) + { + LPMINMAXINFO lpMMI = (LPMINMAXINFO)lParam; + lpMMI->ptMinTrackSize = m_ptMinTrackSize; + } + return 0; + } +#endif // _WIN32_WCE + +// Implementation + bool DlgResize_PositionControl(int cxWidth, int cyHeight, RECT& rectGroup, _AtlDlgResizeData& data, bool bGroup, + _AtlDlgResizeData* pDataPrev = NULL) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + ATL::CWindow ctl; + RECT rectCtl = { 0 }; + + ctl = pT->GetDlgItem(data.m_nCtlID); + if(!ctl.GetWindowRect(&rectCtl)) + return false; + ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rectCtl, 2); + + if(bGroup) + { + if((data.m_dwResizeFlags & DLSZ_CENTER_X) != 0) + { + int cxRight = rectGroup.right + cxWidth - m_sizeDialog.cx; + int cxCtl = data.m_rect.right - data.m_rect.left; + rectCtl.left = rectGroup.left + (cxRight - rectGroup.left - cxCtl) / 2; + rectCtl.right = rectCtl.left + cxCtl; + } + else if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_MOVE_X)) != 0) + { + rectCtl.left = rectGroup.left + ::MulDiv(data.m_rect.left - rectGroup.left, rectGroup.right - rectGroup.left + (cxWidth - m_sizeDialog.cx), rectGroup.right - rectGroup.left); + + if((data.m_dwResizeFlags & DLSZ_SIZE_X) != 0) + { + rectCtl.right = rectGroup.left + ::MulDiv(data.m_rect.right - rectGroup.left, rectGroup.right - rectGroup.left + (cxWidth - m_sizeDialog.cx), rectGroup.right - rectGroup.left); + + if(pDataPrev != NULL) + { + ATL::CWindow ctlPrev = pT->GetDlgItem(pDataPrev->m_nCtlID); + RECT rcPrev = { 0 }; + ctlPrev.GetWindowRect(&rcPrev); + ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rcPrev, 2); + int dxAdjust = (rectCtl.left - rcPrev.right) - (data.m_rect.left - pDataPrev->m_rect.right); + rcPrev.right += dxAdjust; + ctlPrev.SetWindowPos(NULL, &rcPrev, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE); + } + } + else + { + rectCtl.right = rectCtl.left + (data.m_rect.right - data.m_rect.left); + } + } + + if((data.m_dwResizeFlags & DLSZ_CENTER_Y) != 0) + { + int cyBottom = rectGroup.bottom + cyHeight - m_sizeDialog.cy; + int cyCtl = data.m_rect.bottom - data.m_rect.top; + rectCtl.top = rectGroup.top + (cyBottom - rectGroup.top - cyCtl) / 2; + rectCtl.bottom = rectCtl.top + cyCtl; + } + else if((data.m_dwResizeFlags & (DLSZ_SIZE_Y | DLSZ_MOVE_Y)) != 0) + { + rectCtl.top = rectGroup.top + ::MulDiv(data.m_rect.top - rectGroup.top, rectGroup.bottom - rectGroup.top + (cyHeight - m_sizeDialog.cy), rectGroup.bottom - rectGroup.top); + + if((data.m_dwResizeFlags & DLSZ_SIZE_Y) != 0) + { + rectCtl.bottom = rectGroup.top + ::MulDiv(data.m_rect.bottom - rectGroup.top, rectGroup.bottom - rectGroup.top + (cyHeight - m_sizeDialog.cy), rectGroup.bottom - rectGroup.top); + + if(pDataPrev != NULL) + { + ATL::CWindow ctlPrev = pT->GetDlgItem(pDataPrev->m_nCtlID); + RECT rcPrev = { 0 }; + ctlPrev.GetWindowRect(&rcPrev); + ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rcPrev, 2); + int dxAdjust = (rectCtl.top - rcPrev.bottom) - (data.m_rect.top - pDataPrev->m_rect.bottom); + rcPrev.bottom += dxAdjust; + ctlPrev.SetWindowPos(NULL, &rcPrev, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE); + } + } + else + { + rectCtl.bottom = rectCtl.top + (data.m_rect.bottom - data.m_rect.top); + } + } + } + else // no group + { + if((data.m_dwResizeFlags & DLSZ_CENTER_X) != 0) + { + int cxCtl = data.m_rect.right - data.m_rect.left; + rectCtl.left = (cxWidth - cxCtl) / 2; + rectCtl.right = rectCtl.left + cxCtl; + } + else if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_MOVE_X)) != 0) + { + rectCtl.right = data.m_rect.right + (cxWidth - m_sizeDialog.cx); + + if((data.m_dwResizeFlags & DLSZ_MOVE_X) != 0) + rectCtl.left = rectCtl.right - (data.m_rect.right - data.m_rect.left); + } + + if((data.m_dwResizeFlags & DLSZ_CENTER_Y) != 0) + { + int cyCtl = data.m_rect.bottom - data.m_rect.top; + rectCtl.top = (cyHeight - cyCtl) / 2; + rectCtl.bottom = rectCtl.top + cyCtl; + } + else if((data.m_dwResizeFlags & (DLSZ_SIZE_Y | DLSZ_MOVE_Y)) != 0) + { + rectCtl.bottom = data.m_rect.bottom + (cyHeight - m_sizeDialog.cy); + + if((data.m_dwResizeFlags & DLSZ_MOVE_Y) != 0) + rectCtl.top = rectCtl.bottom - (data.m_rect.bottom - data.m_rect.top); + } + } + + if((data.m_dwResizeFlags & DLSZ_REPAINT) != 0) + ctl.Invalidate(); + + if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_SIZE_Y | DLSZ_MOVE_X | DLSZ_MOVE_Y | DLSZ_REPAINT | DLSZ_CENTER_X | DLSZ_CENTER_Y)) != 0) + ctl.SetWindowPos(NULL, &rectCtl, SWP_NOZORDER | SWP_NOACTIVATE); + + return true; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CDoubleBufferImpl - Provides double-buffer painting support to any window + +template +class CDoubleBufferImpl +{ +public: +// Overrideables + void DoPaint(CDCHandle /*dc*/) + { + // must be implemented in a derived class + ATLASSERT(FALSE); + } + +// Message map and handlers + BEGIN_MSG_MAP(CDoubleBufferImpl) + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) + MESSAGE_HANDLER(WM_PAINT, OnPaint) +#ifndef _WIN32_WCE + MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) +#endif // !_WIN32_WCE + END_MSG_MAP() + + LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return 1; // no background painting needed + } + + LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + + if(wParam != NULL) + { + RECT rect = { 0 }; + pT->GetClientRect(&rect); + CMemoryDC dcMem((HDC)wParam, rect); + pT->DoPaint(dcMem.m_hDC); + } + else + { + CPaintDC dc(pT->m_hWnd); + CMemoryDC dcMem(dc.m_hDC, dc.m_ps.rcPaint); + pT->DoPaint(dcMem.m_hDC); + } + + return 0; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CDoubleBufferWindowImpl - Implements a double-buffer painting window + +template +class ATL_NO_VTABLE CDoubleBufferWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CDoubleBufferImpl< T > +{ +public: + BEGIN_MSG_MAP(CDoubleBufferWindowImpl) + CHAIN_MSG_MAP(CDoubleBufferImpl< T >) + END_MSG_MAP() +}; + + +// command bar support +#if !defined(__ATLCTRLW_H__) && !defined(_WIN32_WCE) + #undef CBRM_GETMENU + #undef CBRM_TRACKPOPUPMENU + #undef CBRM_GETCMDBAR + #undef CBRPOPUPMENU +#endif // !defined(__ATLCTRLW_H__) && !defined(_WIN32_WCE) + +}; // namespace WTL + +#endif // __ATLFRAME_H__ -- cgit v1.2.3