// Win32++   Version 7.2
// Released: 5th AUgust 2011
//
//      David Nash
//      email: dnash@bigpond.net.au
//      url: https://sourceforge.net/projects/win32-framework
//
//
// Copyright (c) 2005-2011  David Nash
//
// Permission is hereby granted, free of charge, to
// any person obtaining a copy of this software and
// associated documentation files (the "Software"),
// to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify,
// merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom
// the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice
// shall be included in all copies or substantial portions
// of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
// OR OTHER DEALINGS IN THE SOFTWARE.
//
////////////////////////////////////////////////////////


////////////////////////////////////////////////////////
// dialog.h
//  Declaration of the CDialog class

// CDialog adds support for dialogs to Win32++. Dialogs are specialised
// windows which are a parent window for common controls. Common controls
// are special window types such as buttons, edit controls, tree views,
// list views, static text etc.

// The layout of a dialog is typically defined in a resource script file
// (often Resource.rc). While this script file can be constructed manually,
// it is often created using a resource editor. If your compiler doesn't
// include a resource editor, you might find ResEdit useful. It is a free
// resource editor available for download at:
// http://www.resedit.net/

// CDialog supports modal and modeless dialogs. It also supports the creation
// of dialogs defined in a resource script file, as well as those defined in
// a dialog template.

// Use the Dialog generic program as the starting point for your own dialog
// applications.
// The DlgSubclass sample demonstrates how to use subclassing to customise
// the behaviour of common controls in a dialog.


#ifndef _WIN32XX_DIALOG_H_
#define _WIN32XX_DIALOG_H_

#include "wincore.h"

#ifndef SWP_NOCOPYBITS
	#define SWP_NOCOPYBITS      0x0100
#endif

namespace Win32xx
{

	class CDialog : public CWnd
	{
	public:
		CDialog(UINT nResID, CWnd* pParent = NULL);
		CDialog(LPCTSTR lpszResName, CWnd* pParent = NULL);
		CDialog(LPCDLGTEMPLATE lpTemplate, CWnd* pParent = NULL);
		virtual ~CDialog();

		// You probably won't need to override these functions
		virtual void AttachItem(int nID, CWnd& Wnd);
		virtual HWND Create(CWnd* pParent = NULL);
		virtual INT_PTR DoModal();
		virtual HWND DoModeless();
		virtual void SetDlgParent(CWnd* pParent);
		BOOL IsModal() const { return m_IsModal; }
		BOOL IsIndirect() const { return (NULL != m_lpTemplate); }

	protected:
		// These are the functions you might wish to override
		virtual INT_PTR DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
		virtual INT_PTR DialogProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam);
		virtual void EndDialog(INT_PTR nResult);
		virtual void OnCancel();
		virtual BOOL OnInitDialog();
		virtual void OnOK();
		virtual BOOL PreTranslateMessage(MSG* pMsg);

		// Can't override these functions
		static INT_PTR CALLBACK StaticDialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

	#ifndef _WIN32_WCE
		static LRESULT CALLBACK StaticMsgHook(int nCode, WPARAM wParam, LPARAM lParam);
	#endif

	private:
		CDialog(const CDialog&);			  // Disable copy construction
		CDialog& operator = (const CDialog&); // Disable assignment operator

		BOOL m_IsModal;					// a flag for modal dialogs
		LPCTSTR m_lpszResName;			// the resource name for the dialog
		LPCDLGTEMPLATE m_lpTemplate;	// the dialog template for indirect dialogs
		HWND m_hParent;					// handle to the dialogs's parent window
	};


#ifndef _WIN32_WCE

    //////////////////////////////////////
    // Declaration of the CResizer class
    //
    // The CResizer class can be used to rearrange a dialog's child
    // windows when the dialog is resized.

    // To use CResizer, follow the following steps:
    // 1) Use Initialize to specify the dialog's CWnd, and min and max size.
    // 3) Use AddChild for each child window
    // 4) Call HandleMessage from within DialogProc.
    //

	// Resize Dialog Styles
#define RD_STRETCH_WIDTH		0x0001	// The item has a variable width
#define RD_STRETCH_HEIGHT		0x0002	// The item has a variable height

	// Resize Dialog alignments
	enum Alignment { topleft, topright, bottomleft, bottomright };

    class CResizer
    {
	public:
		CResizer() : m_pParent(0), m_xScrollPos(0), m_yScrollPos(0) {}
		virtual ~CResizer() {}

        virtual void AddChild(CWnd* pWnd, Alignment corner, DWORD dwStyle);
		virtual void AddChild(HWND hWnd, Alignment corner, DWORD dwStyle);
		virtual void HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
    	virtual void Initialize(CWnd* pParent, RECT rcMin, RECT rcMax = CRect(0,0,0,0));
		virtual void OnHScroll(WPARAM wParam, LPARAM lParam);
		virtual void OnVScroll(WPARAM wParam, LPARAM lParam);
		virtual void RecalcLayout();
		CRect GetMinRect() const { return m_rcMin; }
		CRect GetMaxRect() const { return m_rcMax; }

		struct ResizeData
		{
			CRect rcInit;
			CRect rcOld;
			Alignment corner;
			BOOL bFixedWidth;
			BOOL bFixedHeight;
    		HWND hWnd;
		};

    private:
        CWnd* m_pParent;
    	std::vector<ResizeData> m_vResizeData;

    	CRect m_rcInit;
    	CRect m_rcMin;
    	CRect m_rcMax;

		int m_xScrollPos;
		int m_yScrollPos;
    };

#endif

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


namespace Win32xx
{
    ////////////////////////////////////
	// Definitions for the CDialog class
	//
	inline CDialog::CDialog(LPCTSTR lpszResName, CWnd* pParent/* = NULL*/)
		: m_IsModal(TRUE), m_lpszResName(lpszResName), m_lpTemplate(NULL)
	{
		m_hParent = pParent? pParent->GetHwnd() : NULL;
		::InitCommonControls();
	}

	inline CDialog::CDialog(UINT nResID, CWnd* pParent/* = NULL*/)
		: m_IsModal(TRUE), m_lpszResName(MAKEINTRESOURCE (nResID)), m_lpTemplate(NULL)
	{
		m_hParent = pParent? pParent->GetHwnd() : NULL;
		::InitCommonControls();
	}

	//For indirect dialogs - created from a dialog box template in memory.
	inline CDialog::CDialog(LPCDLGTEMPLATE lpTemplate, CWnd* pParent/* = NULL*/)
		: m_IsModal(TRUE), m_lpszResName(NULL), m_lpTemplate(lpTemplate)
	{
		m_hParent = pParent? pParent->GetHwnd() : NULL;
		::InitCommonControls();
	}

	inline CDialog::~CDialog()
	{
		if (m_hWnd != NULL)
		{
			if (IsModal())
				::EndDialog(m_hWnd, 0);
			else
				Destroy();
		}
	}

	inline void CDialog::AttachItem(int nID, CWnd& Wnd)
	// Attach a dialog item to a CWnd
	{
		Wnd.AttachDlgItem(nID, this);
	}

	inline HWND CDialog::Create(CWnd* pParent /* = NULL */)
	{
		// Allow a dialog to be used as a child window

		assert(GetApp());
		SetDlgParent(pParent);
		return DoModeless();
	}

	inline INT_PTR CDialog::DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
	{
		// Override this function in your class derrived from CDialog if you wish to handle messages
		// A typical function might look like this:

		//	switch (uMsg)
		//	{
		//	case MESSAGE1:		// Some Windows API message
		//		OnMessage1();	// A user defined function
		//		break;			// Also do default processing
		//	case MESSAGE2:
		//		OnMessage2();
		//		return x;		// Don't do default processing, but instead return
		//						//  a value recommended by the Windows API documentation
		//	}

		// Always pass unhandled messages on to DialogProcDefault
		return DialogProcDefault(uMsg, wParam, lParam);
	}

	inline INT_PTR CDialog::DialogProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam)
	// All DialogProc functions should pass unhandled messages to this function
	{
		LRESULT lr = 0;

		switch (uMsg)
	    {
		case UWM_CLEANUPTEMPS:
			{
				TLSData* pTLSData = (TLSData*)TlsGetValue(GetApp()->GetTlsIndex());
				pTLSData->vTmpWnds.clear();
			}
			break;
	    case WM_INITDIALOG:
			{
				// Center the dialog
				CenterWindow();
			}
		    return OnInitDialog();
	    case WM_COMMAND:
	        switch (LOWORD (wParam))
	        {
	        case IDOK:
				OnOK();
				return TRUE;
			case IDCANCEL:
				OnCancel();
				return TRUE;
			default:
				{
					// Refelect this message if it's from a control
					CWnd* pWnd = GetApp()->GetCWndFromMap((HWND)lParam);
					if (pWnd != NULL)
						lr = pWnd->OnCommand(wParam, lParam);

					// Handle user commands
					if (!lr)
						lr =  OnCommand(wParam, lParam);

					if (lr) return 0L;
				}
				break;  // Some commands require default processing
	        }
	        break;

		case WM_NOTIFY:
			{
				// Do Notification reflection if it came from a CWnd object
				HWND hwndFrom = ((LPNMHDR)lParam)->hwndFrom;
				CWnd* pWndFrom = GetApp()->GetCWndFromMap(hwndFrom);

				if (pWndFrom != NULL)
					lr = pWndFrom->OnNotifyReflect(wParam, lParam);
				else
				{
					// Some controls (eg ListView) have child windows.
					// Reflect those notifications too.
					CWnd* pWndFromParent = GetApp()->GetCWndFromMap(::GetParent(hwndFrom));
					if (pWndFromParent != NULL)
						lr = pWndFromParent->OnNotifyReflect(wParam, lParam);
				}
	
				// Handle user notifications
				if (!lr) lr = OnNotify(wParam, lParam);

				// Set the return code for notifications
				if (IsWindow())
					SetWindowLongPtr(DWLP_MSGRESULT, (LONG_PTR)lr);

				return (BOOL)lr;
			}

		case WM_PAINT:
			{
				if (::GetUpdateRect(m_hWnd, NULL, FALSE))
				{
					CPaintDC dc(this);
					OnDraw(&dc);
				}
				else
				// RedrawWindow can require repainting without an update rect
				{
					CClientDC dc(this);
					OnDraw(&dc);
				}

				break;
			}

		case WM_ERASEBKGND:
			{
				CDC dc((HDC)wParam);
				BOOL bResult = OnEraseBkgnd(&dc);
				dc.Detach();
				if (bResult) return TRUE;
			}
			break;

		// A set of messages to be reflected back to the control that generated them
		case WM_CTLCOLORBTN:
		case WM_CTLCOLOREDIT:
		case WM_CTLCOLORDLG:
		case WM_CTLCOLORLISTBOX:
		case WM_CTLCOLORSCROLLBAR:
		case WM_CTLCOLORSTATIC:
		case WM_DRAWITEM:
		case WM_MEASUREITEM:
		case WM_DELETEITEM:
		case WM_COMPAREITEM:
		case WM_CHARTOITEM:
		case WM_VKEYTOITEM:
		case WM_HSCROLL:
		case WM_VSCROLL:
		case WM_PARENTNOTIFY:
			return MessageReflect(m_hWnd, uMsg, wParam, lParam);

	    } // switch(uMsg)
	    return FALSE;

	} // INT_PTR CALLBACK CDialog::DialogProc(...)

	inline INT_PTR CDialog::DoModal()
	{
		// Create a modal dialog
		// A modal dialog box must be closed by the user before the application continues

		assert( GetApp() );		// Test if Win32++ has been started
		assert(!::IsWindow(m_hWnd));	// Only one window per CWnd instance allowed

		INT_PTR nResult = 0;

		try
		{
			m_IsModal=TRUE;

			// Ensure this thread has the TLS index set
			TLSData* pTLSData = GetApp()->SetTlsIndex();

		#ifndef _WIN32_WCE
			BOOL IsHookedHere = FALSE;
			if (NULL == pTLSData->hHook )
			{
				pTLSData->hHook = ::SetWindowsHookEx(WH_MSGFILTER, (HOOKPROC)StaticMsgHook, NULL, ::GetCurrentThreadId());
				IsHookedHere = TRUE;
			}
		#endif

			HINSTANCE hInstance = GetApp()->GetInstanceHandle();
			pTLSData->pCWnd = this;

			// Create a modal dialog
			if (IsIndirect())
				nResult = ::DialogBoxIndirect(hInstance, m_lpTemplate, m_hParent, (DLGPROC)CDialog::StaticDialogProc);
			else
			{
				if (::FindResource(GetApp()->GetResourceHandle(), m_lpszResName, RT_DIALOG))
					hInstance = GetApp()->GetResourceHandle();
				nResult = ::DialogBox(hInstance, m_lpszResName, m_hParent, (DLGPROC)CDialog::StaticDialogProc);
			}

			// Tidy up
			m_hWnd = NULL;
			pTLSData->pCWnd = NULL;
			GetApp()->CleanupTemps();

		#ifndef _WIN32_WCE
			if (IsHookedHere)
			{
				::UnhookWindowsHookEx(pTLSData->hHook);
				pTLSData->hHook = NULL;
			}
		#endif

			if (nResult == -1)
				throw CWinException(_T("Failed to create modal dialog box"));

		}

		catch (const CWinException &e)
		{
			TRACE(_T("\n*** Failed to create dialog ***\n"));
			e.what();	// Display the last error message.

			// eat the exception (don't rethrow)
		}

		return nResult;
	}

	inline HWND CDialog::DoModeless()
	{
		assert( GetApp() );		// Test if Win32++ has been started
		assert(!::IsWindow(m_hWnd));	// Only one window per CWnd instance allowed

		try
		{
			m_IsModal=FALSE;

			// Ensure this thread has the TLS index set
			TLSData* pTLSData = GetApp()->SetTlsIndex();

			// Store the CWnd pointer in Thread Local Storage
			pTLSData->pCWnd = this;

			HINSTANCE hInstance = GetApp()->GetInstanceHandle();

			// Create a modeless dialog
			if (IsIndirect())
				m_hWnd = ::CreateDialogIndirect(hInstance, m_lpTemplate, m_hParent, (DLGPROC)CDialog::StaticDialogProc);
			else
			{
				if (::FindResource(GetApp()->GetResourceHandle(), m_lpszResName, RT_DIALOG))
					hInstance = GetApp()->GetResourceHandle();

				m_hWnd = ::CreateDialog(hInstance, m_lpszResName, m_hParent, (DLGPROC)CDialog::StaticDialogProc);
			}

			// Tidy up
			pTLSData->pCWnd = NULL;

			// Now handle dialog creation failure
			if (!m_hWnd)
				throw CWinException(_T("Failed to create dialog"));
		}

		catch (const CWinException &e)
		{
			TRACE(_T("\n*** Failed to create dialog ***\n"));
			e.what();	// Display the last error message.

			// eat the exception (don't rethrow)
		}

		return m_hWnd;
	}

	inline void CDialog::EndDialog(INT_PTR nResult)
	{
		assert(::IsWindow(m_hWnd));

		if (IsModal())
			::EndDialog(m_hWnd, nResult);
		else
			Destroy();

		m_hWnd = NULL;
	}

	inline void CDialog::OnCancel()
	{
		// Override to customize OnCancel behaviour
		EndDialog(IDCANCEL);
	}

	inline BOOL CDialog::OnInitDialog()
	{
		// Called when the dialog is initialized
		// Override it in your derived class to automatically perform tasks
		// The return value is used by WM_INITDIALOG

		return TRUE;
	}

	inline void CDialog::OnOK()
	{
		// Override to customize OnOK behaviour
		EndDialog(IDOK);
	}

	inline BOOL CDialog::PreTranslateMessage(MSG* pMsg)
	{
		// allow the dialog to translate keyboard input
		if ((pMsg->message >= WM_KEYFIRST) && (pMsg->message <= WM_KEYLAST))
		{
			// Process dialog keystrokes for modeless dialogs
			if (!IsModal())
			{
				TLSData* pTLSData = (TLSData*)TlsGetValue(GetApp()->GetTlsIndex());
				if (NULL == pTLSData->hHook)
				{
					if (IsDialogMessage(pMsg))
						return TRUE;
				}
				else
				{
					// A modal message loop is running so we can't do IsDialogMessage.
					// Avoid having modal dialogs create other windows, because those
					// windows will then use the modal dialog's special message loop.
				}
			}
		}

		return FALSE;
	}

	inline void CDialog::SetDlgParent(CWnd* pParent)
	// Allows the parent of the dialog to be set before the dialog is created
	{
		m_hParent = pParent? pParent->GetHwnd() : NULL;
	}

	inline INT_PTR CALLBACK CDialog::StaticDialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
	{
		// Find the CWnd pointer mapped to this HWND
		CDialog* w = (CDialog*)GetApp()->GetCWndFromMap(hWnd);
		if (0 == w)
		{
			// The HWND wasn't in the map, so add it now
			TLSData* pTLSData = (TLSData*)TlsGetValue(GetApp()->GetTlsIndex());
			assert(pTLSData);

			// Retrieve pointer to CWnd object from Thread Local Storage TLS
			w = (CDialog*)pTLSData->pCWnd;
			assert(w);
			pTLSData->pCWnd = NULL;

			// Store the Window pointer into the HWND map
			w->m_hWnd = hWnd;
			w->AddToMap();
		}

		return w->DialogProc(uMsg, wParam, lParam);

	} // INT_PTR CALLBACK CDialog::StaticDialogProc(...)

#ifndef _WIN32_WCE
	inline LRESULT CALLBACK CDialog::StaticMsgHook(int nCode, WPARAM wParam, LPARAM lParam)
	{
		// Used by Modal Dialogs to PreTranslate Messages
		TLSData* pTLSData = (TLSData*)TlsGetValue(GetApp()->GetTlsIndex());

		if (nCode == MSGF_DIALOGBOX)
		{
			MSG* lpMsg = (MSG*) lParam;

			// only pre-translate keyboard events
			if ((lpMsg->message >= WM_KEYFIRST && lpMsg->message <= WM_KEYLAST))
			{
				for (HWND hWnd = lpMsg->hwnd; hWnd != NULL; hWnd = ::GetParent(hWnd))
				{
					CDialog* pDialog = (CDialog*)GetApp()->GetCWndFromMap(hWnd);
					if (pDialog && (lstrcmp(pDialog->GetClassName(), _T("#32770")) == 0))	// only for dialogs
					{
						pDialog->PreTranslateMessage(lpMsg);
						break;
					}
				}
			}
		}

		return ::CallNextHookEx(pTLSData->hHook, nCode, wParam, lParam);
	}
#endif



#ifndef _WIN32_WCE

    /////////////////////////////////////
	// Definitions for the CResizer class
	//

	void inline CResizer::AddChild(CWnd* pWnd, Alignment corner, DWORD dwStyle)
    // Adds a child window (usually a dialog control) to the set of windows managed by
	// the Resizer.
	//
	// The alignment corner should be set to the closest corner of the dialog. Allowed
	// values are topleft, topright, bottomleft, and bottomright.
	// Set bFixedWidth to TRUE if the width should be fixed instead of variable.
	// Set bFixedHeight to TRUE if the height should be fixed instead of variable.
	{
    	ResizeData rd;
    	rd.corner = corner;
    	rd.bFixedWidth  = !(dwStyle & RD_STRETCH_WIDTH);
    	rd.bFixedHeight = !(dwStyle & RD_STRETCH_HEIGHT);
		CRect rcInit = pWnd->GetWindowRect();
		m_pParent->ScreenToClient(rcInit);
		rd.rcInit = rcInit;
		rd.hWnd = pWnd->GetHwnd();

		m_vResizeData.insert(m_vResizeData.begin(), rd);
    }

	void inline CResizer::AddChild(HWND hWnd, Alignment corner, DWORD dwStyle)
    // Adds a child window (usually a dialog control) to the set of windows managed by
	// the Resizer.	
	{
		AddChild(FromHandle(hWnd), corner, dwStyle);
	}

	inline void CResizer::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
	{
		switch (uMsg)
		{
		case WM_SIZE:
			RecalcLayout();
			break;

		case WM_HSCROLL:
			if (0 == lParam)
				OnHScroll(wParam, lParam);
			break;

		case WM_VSCROLL:
			if (0 == lParam)
				OnVScroll(wParam, lParam);
			break;
		}
	}

    void inline CResizer::Initialize(CWnd* pParent, RECT rcMin, RECT rcMax)
	// Sets up the Resizer by specifying the parent window (usually a dialog),
	//  and the minimum and maximum allowed rectangle sizes.
    {
    	assert (NULL != pParent);

    	m_pParent = pParent;
    	m_rcInit = pParent->GetClientRect();
    	m_rcMin = rcMin;
    	m_rcMax = rcMax;

		// Add scroll bar support to the parent window
		DWORD dwStyle = (DWORD)m_pParent->GetClassLongPtr(GCL_STYLE);
		dwStyle |= WS_HSCROLL | WS_VSCROLL;
		m_pParent->SetClassLongPtr(GCL_STYLE, dwStyle);
    }

	void inline CResizer::OnHScroll(WPARAM wParam, LPARAM /*lParam*/)
	{
		int xNewPos;

		switch (LOWORD(wParam))
		{
			case SB_PAGEUP: // User clicked the scroll bar shaft left of the scroll box.
				xNewPos = m_xScrollPos - 50;
				break;

			case SB_PAGEDOWN: // User clicked the scroll bar shaft right of the scroll box.
				xNewPos = m_xScrollPos + 50;
				break;

			case SB_LINEUP: // User clicked the left arrow.
				xNewPos = m_xScrollPos - 5;
				break;

			case SB_LINEDOWN: // User clicked the right arrow.
				xNewPos = m_xScrollPos + 5;
				break;

			case SB_THUMBPOSITION: // User dragged the scroll box.
				xNewPos = HIWORD(wParam);
				break;

			case SB_THUMBTRACK: // User dragging the scroll box.
				xNewPos = HIWORD(wParam);
				break;

			default:
				xNewPos = m_xScrollPos;
		}

		// Scroll the window.
		xNewPos = MAX(0, xNewPos);
		xNewPos = MIN( xNewPos, GetMinRect().Width() - m_pParent->GetClientRect().Width() );
		int xDelta = xNewPos - m_xScrollPos;
		m_xScrollPos = xNewPos;
		m_pParent->ScrollWindow(-xDelta, 0, NULL, NULL);

		// Reset the scroll bar.
		SCROLLINFO si = {0};
		si.cbSize = sizeof(si);
		si.fMask  = SIF_POS;
		si.nPos   = m_xScrollPos;
		m_pParent->SetScrollInfo(SB_HORZ, si, TRUE);
	}

	void inline CResizer::OnVScroll(WPARAM wParam, LPARAM /*lParam*/)
	{
		int yNewPos;

		switch (LOWORD(wParam))
		{
			case SB_PAGEUP: // User clicked the scroll bar shaft above the scroll box.
				yNewPos = m_yScrollPos - 50;
				break;

			case SB_PAGEDOWN: // User clicked the scroll bar shaft below the scroll box.
				yNewPos = m_yScrollPos + 50;
				break;

			case SB_LINEUP: // User clicked the top arrow.
				yNewPos = m_yScrollPos - 5;
				break;

			case SB_LINEDOWN: // User clicked the bottom arrow.
				yNewPos = m_yScrollPos + 5;
				break;

			case SB_THUMBPOSITION: // User dragged the scroll box.
				yNewPos = HIWORD(wParam);
				break;

			case SB_THUMBTRACK: // User dragging the scroll box.
				yNewPos = HIWORD(wParam);
				break;

			default:
				yNewPos = m_yScrollPos;
		}

		// Scroll the window.
		yNewPos = MAX(0, yNewPos);
		yNewPos = MIN( yNewPos, GetMinRect().Height() - m_pParent->GetClientRect().Height() );
		int yDelta = yNewPos - m_yScrollPos;
		m_yScrollPos = yNewPos;
		m_pParent->ScrollWindow(0, -yDelta, NULL, NULL);

		// Reset the scroll bar.
		SCROLLINFO si = {0};
		si.cbSize = sizeof(si);
		si.fMask  = SIF_POS;
		si.nPos   = m_yScrollPos;
		m_pParent->SetScrollInfo(SB_VERT, si, TRUE);
	}

    void inline CResizer::RecalcLayout()
    // Repositions the child windows. Call this function when handling
	// the WM_SIZE message in the parent window.
	{
    	assert (m_rcInit.Width() > 0 && m_rcInit.Height() > 0);
    	assert (NULL != m_pParent);

		CRect rcCurrent = m_pParent->GetClientRect();

		// Adjust the scrolling if required
		m_xScrollPos = MIN(m_xScrollPos, MAX(0, m_rcMin.Width()  - rcCurrent.Width() ) );
		m_yScrollPos = MIN(m_yScrollPos, MAX(0, m_rcMin.Height() - rcCurrent.Height()) );
		SCROLLINFO si = {0};
		si.cbSize = sizeof(si);
		si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;
		si.nMax   =	m_rcMin.Width();
		si.nPage  = rcCurrent.Width();
		si.nPos   = m_xScrollPos;
		m_pParent->SetScrollInfo(SB_HORZ, si, TRUE);
		si.nMax   =	m_rcMin.Height();
		si.nPage  = rcCurrent.Height();
		si.nPos   = m_yScrollPos;
		m_pParent->SetScrollInfo(SB_VERT, si, TRUE);

    	rcCurrent.right  = MAX( rcCurrent.Width(),  m_rcMin.Width() );
    	rcCurrent.bottom = MAX( rcCurrent.Height(), m_rcMin.Height() );
    	if (!m_rcMax.IsRectEmpty())
    	{
    		rcCurrent.right  = MIN( rcCurrent.Width(),  m_rcMax.Width() );
    		rcCurrent.bottom = MIN( rcCurrent.Height(), m_rcMax.Height() );
    	}

		// Declare an iterator to step through the vector
		std::vector<ResizeData>::iterator iter;

    	for (iter = m_vResizeData.begin(); iter < m_vResizeData.end(); ++iter)
    	{
    		int left   = 0;
    		int top    = 0;
    		int width  = 0;
    		int height = 0;

    		// Calculate the new size and position of the child window
			switch( (*iter).corner )
    		{
    		case topleft:
				width  = (*iter).bFixedWidth?  (*iter).rcInit.Width()  : (*iter).rcInit.Width()  - m_rcInit.Width() + rcCurrent.Width();
    			height = (*iter).bFixedHeight? (*iter).rcInit.Height() : (*iter).rcInit.Height() - m_rcInit.Height() + rcCurrent.Height();
    			left   = (*iter).rcInit.left;
    			top    = (*iter).rcInit.top;
    			break;
    		case topright:
    			width  = (*iter).bFixedWidth?  (*iter).rcInit.Width()  : (*iter).rcInit.Width()  - m_rcInit.Width() + rcCurrent.Width();
    			height = (*iter).bFixedHeight? (*iter).rcInit.Height() : (*iter).rcInit.Height() - m_rcInit.Height() + rcCurrent.Height();
    			left   = (*iter).rcInit.right - width - m_rcInit.Width() + rcCurrent.Width();
    			top    = (*iter).rcInit.top;
    			break;
    		case bottomleft:
				width  = (*iter).bFixedWidth?  (*iter).rcInit.Width()  : (*iter).rcInit.Width()  - m_rcInit.Width() + rcCurrent.Width();
    			height = (*iter).bFixedHeight? (*iter).rcInit.Height() : (*iter).rcInit.Height() - m_rcInit.Height() + rcCurrent.Height();
    			left   = (*iter).rcInit.left;
    			top    = (*iter).rcInit.bottom - height - m_rcInit.Height() + rcCurrent.Height();
    			break;
    		case bottomright:
    			width  = (*iter).bFixedWidth?  (*iter).rcInit.Width()  : (*iter).rcInit.Width()  - m_rcInit.Width() + rcCurrent.Width();
    			height = (*iter).bFixedHeight? (*iter).rcInit.Height() : (*iter).rcInit.Height() - m_rcInit.Height() + rcCurrent.Height();
    			left   = (*iter).rcInit.right   - width - m_rcInit.Width() + rcCurrent.Width();
    			top    = (*iter).rcInit.bottom  - height - m_rcInit.Height() + rcCurrent.Height();
    			break;
    		}

			// Position the child window.
			CRect rc(left - m_xScrollPos, top - m_yScrollPos, left + width - m_xScrollPos, top + height - m_yScrollPos);
			if ( rc != (*iter).rcOld)
			{
				CWnd* pWnd = FromHandle((*iter).hWnd);
				CWnd *pWndPrev = pWnd->GetWindow(GW_HWNDPREV); // Trick to maintain the original tab order.
				HWND hWnd = pWndPrev ? pWndPrev->GetHwnd():NULL;
				pWnd->SetWindowPos(hWnd, rc, SWP_NOCOPYBITS);
				(*iter).rcOld = rc;
			}
    	}
    }

#endif // #ifndef _WIN32_WCE

} // namespace Win32xx



#endif // _WIN32XX_DIALOG_H_