// 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.
//
////////////////////////////////////////////////////////


////////////////////////////////////////////////////////
// mdi.h
//  Declaration of the CMDIChild and CMDIFrame classes

// The classes defined here add MDI frames support to Win32++. MDI
// (Multiple Document Interface) frames host one or more child windows. The
// child windows hosted by a MDI frame can be different types. For example,
// some MDI child windows could be used to edit text, while others could be
// used to display a bitmap. Four classes are defined here to support MDI
// frames:


// 1) CMDIFrame. This class inherits from CFrame, and adds the functionality
//    required by MDI frames. It keeps track of the MDI children created and
//    destroyed, and adjusts the menu when a MDI child is activated. Use the
//    AddMDIChild function to add MDI child windows to the MDI frame. Inherit
//    from CMDIFrame to create your own MDI frame.
//
// 2) CMDIChild: All MDI child windows (ie. CWnd classes) should inherit from
//    this class. Each MDI child type can have a different frame menu.

// Use the MDIFrame generic application as the starting point for your own MDI
// frame applications.
// Refer to the MDIDemo sample for an example on how to use these classes to
// create a MDI frame application with different types of MDI child windows.


#ifndef _WIN32XX_MDI_H_
#define _WIN32XX_MDI_H_

#include "frame.h"
#include <vector>



namespace Win32xx
{
    class CMDIChild;
    class CMDIFrame;
	typedef Shared_Ptr<CMDIChild> MDIChildPtr;

	/////////////////////////////////////
	// Declaration of the CMDIChild class
	//
	class CMDIChild : public CWnd
	{
		friend class CMDIFrame;
	public:
		CMDIChild();
		virtual ~CMDIChild();

		// These are the functions you might wish to override
		virtual HWND Create(CWnd* pParent = NULL);
		virtual void RecalcLayout();

		// These functions aren't virtual, and shouldn't be overridden
		void SetHandles(HMENU MenuName, HACCEL AccelName);
		CMDIFrame* GetMDIFrame() const;
		CWnd* GetView() const	{return m_pView;}
		void SetView(CWnd& pwndView);
		void MDIActivate() const;
		void MDIDestroy() const;
		void MDIMaximize() const;
		void MDIRestore() const;

	protected:
		// Its unlikely you would need to override these functions
		virtual LRESULT FinalWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
		virtual void OnCreate();
		virtual LRESULT WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam);

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

		CWnd* m_pView;				// pointer to the View CWnd object
		HMENU m_hChildMenu;
		HACCEL m_hChildAccel;
	};


	/////////////////////////////////////
	// Declaration of the CMDIFrame class
	//
	class CMDIFrame : public CFrame
	{
		friend class CMDIChild;     // CMDIChild uses m_hOrigMenu
		typedef Shared_Ptr<CMDIChild> MDIChildPtr;

	public:
		class CMDIClient : public CWnd  // a nested class within CMDIFrame
		{
		public:
			CMDIClient() {}
			virtual ~CMDIClient() {}
			virtual HWND Create(CWnd* pParent = NULL);
			virtual LRESULT WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
			CMDIFrame* GetMDIFrame() const { return (CMDIFrame*)GetParent(); }

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


		CMDIFrame();
		virtual ~CMDIFrame() {}

		virtual CMDIChild* AddMDIChild(MDIChildPtr pMDIChild);
		virtual CMDIClient& GetMDIClient() const { return (CMDIClient&)m_MDIClient; }
		virtual BOOL IsMDIFrame() const { return TRUE; }
		virtual void RemoveMDIChild(HWND hWnd);
		virtual BOOL RemoveAllMDIChildren();
		virtual void UpdateCheckMarks();

		// These functions aren't virtual, so don't override them
		std::vector <MDIChildPtr>& GetAllMDIChildren() {return m_vMDIChild;}
		CMDIChild* GetActiveMDIChild() const;
		BOOL IsMDIChildMaxed() const;
		void MDICascade(int nType = 0) const;
		void MDIIconArrange() const;
		void MDIMaximize() const;
		void MDINext() const;
		void MDIPrev() const;
		void MDIRestore() const;
		void MDITile(int nType = 0) const;
		void SetActiveMDIChild(CMDIChild* pChild);

	protected:
		// These are the functions you might wish to override
		virtual void OnClose();
		virtual void OnViewStatusBar();
		virtual void OnViewToolBar();
		virtual void OnWindowPosChanged();
		virtual void RecalcLayout();
		virtual BOOL PreTranslateMessage(MSG* pMsg);
		virtual LRESULT WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam);

	private:
		CMDIFrame(const CMDIFrame&);				// Disable copy construction
		CMDIFrame& operator = (const CMDIFrame&); // Disable assignment operator
		void AppendMDIMenu(HMENU hMenuWindow);
		LRESULT FinalWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
		void UpdateFrameMenu(HMENU hMenu);

		CMDIClient m_MDIClient;
		std::vector <MDIChildPtr> m_vMDIChild;
		HWND m_hActiveMDIChild;
	};

}


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


namespace Win32xx
{

	/////////////////////////////////////
	// Definitions for the CMDIFrame class
	//
	inline CMDIFrame::CMDIFrame() : m_hActiveMDIChild(NULL)
	{
		SetView(GetMDIClient());
	}

	inline CMDIChild* CMDIFrame::AddMDIChild(MDIChildPtr pMDIChild)
	{
		assert(NULL != pMDIChild.get()); // Cannot add Null MDI Child

		m_vMDIChild.push_back(pMDIChild);
		pMDIChild->Create(GetView());

		return pMDIChild.get();
	}

	inline void CMDIFrame::AppendMDIMenu(HMENU hMenuWindow)
	{
		// Adds the additional menu items the the "Window" submenu when
		//  MDI child windows are created

		if (!IsMenu(hMenuWindow))
			return;

		// Delete previously appended items
		int nItems = ::GetMenuItemCount(hMenuWindow);
		UINT uLastID = ::GetMenuItemID(hMenuWindow, --nItems);
		if ((uLastID >= IDW_FIRSTCHILD) && (uLastID < IDW_FIRSTCHILD + 10))
		{
			while ((uLastID >= IDW_FIRSTCHILD) && (uLastID < IDW_FIRSTCHILD + 10))
			{
				::DeleteMenu(hMenuWindow, nItems, MF_BYPOSITION);
				uLastID = ::GetMenuItemID(hMenuWindow, --nItems);
			}
			//delete the separator too
			::DeleteMenu(hMenuWindow, nItems, MF_BYPOSITION);
		}

		int nWindow = 0;

		// Allocate an iterator for our MDIChild vector
		std::vector <MDIChildPtr>::iterator v;

		for (v = GetAllMDIChildren().begin(); v < GetAllMDIChildren().end(); ++v)
		{
			if ((*v)->GetWindowLongPtr(GWL_STYLE) & WS_VISIBLE)	// IsWindowVisible is unreliable here
			{
				// Add Separator
				if (0 == nWindow)
					::AppendMenu(hMenuWindow, MF_SEPARATOR, 0, NULL);

				// Add a menu entry for each MDI child (up to 9)
				if (nWindow < 9)
				{
					tString tsMenuItem ( (*v)->GetWindowText() );

					if (tsMenuItem.length() > MAX_MENU_STRING -10)
					{
						// Truncate the string if its too long
						tsMenuItem.erase(tsMenuItem.length() - MAX_MENU_STRING +10);
						tsMenuItem += _T(" ...");
					}

					TCHAR szMenuString[MAX_MENU_STRING+1];
					wsprintf(szMenuString, _T("&%d %s"), nWindow+1, tsMenuItem.c_str());

					::AppendMenu(hMenuWindow, MF_STRING, IDW_FIRSTCHILD + nWindow, szMenuString);

					if (GetActiveMDIChild() == (*v).get())
						::CheckMenuItem(hMenuWindow, IDW_FIRSTCHILD+nWindow, MF_CHECKED);

					++nWindow;
				}
				else if (9 == nWindow)
				// For the 10th MDI child, add this menu item and return
				{
					::AppendMenu(hMenuWindow, MF_STRING, IDW_FIRSTCHILD + nWindow, _T("&Windows..."));
					return;
				}
			}
		}
	}

	inline LRESULT CMDIFrame::FinalWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
	{
		return ::DefFrameProc(m_hWnd, GetMDIClient(), uMsg, wParam, lParam);
	}

	inline CMDIChild* CMDIFrame::GetActiveMDIChild() const
	{
		return (CMDIChild*)FromHandle(m_hActiveMDIChild);
	}

	inline BOOL CMDIFrame::IsMDIChildMaxed() const
	{
		BOOL bMaxed = FALSE;
		GetMDIClient().SendMessage(WM_MDIGETACTIVE, 0L, (LPARAM)&bMaxed);
		return bMaxed;
	}

	inline void CMDIFrame::MDICascade(int nType /* = 0*/) const
	{
		// Possible values for nType are:
		// MDITILE_SKIPDISABLED	Prevents disabled MDI child windows from being cascaded.

		assert(::IsWindow(m_hWnd));
		GetView()->SendMessage(WM_MDICASCADE, (WPARAM)nType, 0L);
	}

	inline void CMDIFrame::MDIIconArrange() const
	{
		assert(::IsWindow(m_hWnd));
		GetView()->SendMessage(WM_MDIICONARRANGE, 0L, 0L);
	}

	inline void CMDIFrame::MDIMaximize() const
	{
		assert(::IsWindow(m_hWnd));
		GetView()->SendMessage(WM_MDIMAXIMIZE, 0L, 0L);
	}

	inline void CMDIFrame::MDINext() const
	{
		assert(::IsWindow(m_hWnd));
		HWND hMDIChild = GetActiveMDIChild()->GetHwnd();
		GetView()->SendMessage(WM_MDINEXT, (WPARAM)hMDIChild, FALSE);
	}

	inline void CMDIFrame::MDIPrev() const
	{
		assert(::IsWindow(m_hWnd));
		HWND hMDIChild = GetActiveMDIChild()->GetHwnd();
		GetView()->SendMessage(WM_MDINEXT, (WPARAM)hMDIChild, TRUE);
	}

	inline void CMDIFrame::MDIRestore() const
	{
		assert(::IsWindow(m_hWnd));
		GetView()->SendMessage(WM_MDIRESTORE, 0L, 0L);
	}

	inline void CMDIFrame::MDITile(int nType /* = 0*/) const
	{
		// Possible values for nType are:
		// MDITILE_HORIZONTAL	Tiles MDI child windows so that one window appears above another.
		// MDITILE_SKIPDISABLED	Prevents disabled MDI child windows from being tiled.
		// MDITILE_VERTICAL		Tiles MDI child windows so that one window appears beside another.

		assert(::IsWindow(m_hWnd));
		GetView()->SendMessage(WM_MDITILE, (WPARAM)nType, 0L);
	}

	inline void CMDIFrame::OnClose()
	{
		if (RemoveAllMDIChildren())
		{
			CFrame::OnClose();
			Destroy();
		}
	}

	inline void CMDIFrame::OnViewStatusBar()
	{
		CFrame::OnViewStatusBar();
		UpdateCheckMarks();
		GetView()->RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN);
	}

	inline void CMDIFrame::OnViewToolBar()
	{
		CFrame::OnViewToolBar();
		UpdateCheckMarks();
		GetView()->RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN);
	}

	inline void CMDIFrame::OnWindowPosChanged()
	{
		if (IsMenuBarUsed())
		{
			// Refresh MenuBar Window
			HMENU hMenu= GetMenuBar().GetMenu();
			GetMenuBar().SetMenu(hMenu);
			UpdateCheckMarks();
		}
	}

	inline BOOL CMDIFrame::PreTranslateMessage(MSG* pMsg)
	{
		if (WM_KEYFIRST <= pMsg->message && pMsg->message <= WM_KEYLAST)
		{
			if (TranslateMDISysAccel(GetView()->GetHwnd(), pMsg))
				return TRUE;
		}

		return CFrame::PreTranslateMessage(pMsg);
	}

	inline void CMDIFrame::RecalcLayout()
	{
		CFrame::RecalcLayout();

		if (GetView()->IsWindow())
			MDIIconArrange();
	}

	inline BOOL CMDIFrame::RemoveAllMDIChildren()
	{
		BOOL bResult = TRUE;
		int Children = (int)m_vMDIChild.size();

		// Remove the children in reverse order
		for (int i = Children-1; i >= 0; --i)
		{
			if (IDNO == m_vMDIChild[i]->SendMessage(WM_CLOSE, 0L, 0L))	// Also removes the MDI child
				bResult = FALSE;
		}

		return bResult;
	}

	inline void CMDIFrame::RemoveMDIChild(HWND hWnd)
	{
		// Allocate an iterator for our HWND map
		std::vector <MDIChildPtr>::iterator v;

		for (v = m_vMDIChild.begin(); v!= m_vMDIChild.end(); ++v)
		{
			if ((*v)->GetHwnd() == hWnd)
			{
				m_vMDIChild.erase(v);
				break;
			}
		}

		if (GetActiveMDIChild())
		{
			if (GetActiveMDIChild()->m_hChildMenu)
				UpdateFrameMenu(GetActiveMDIChild()->m_hChildMenu);
			if (GetActiveMDIChild()->m_hChildAccel)
				GetApp()->SetAccelerators(GetActiveMDIChild()->m_hChildAccel, this);
		}
		else
		{
			if (IsMenuBarUsed())
				GetMenuBar().SetMenu(GetFrameMenu());
			else
				SetMenu(FromHandle(GetFrameMenu()));

			GetApp()->SetAccelerators(GetFrameAccel(), this);
		}
	}

	inline void CMDIFrame::SetActiveMDIChild(CMDIChild* pChild)
	{
		assert ( pChild->IsWindow() );

		GetMDIClient().SendMessage(WM_MDIACTIVATE, (WPARAM)pChild->GetHwnd(), 0L);

		// Verify
		assert ( m_hActiveMDIChild == pChild->GetHwnd() );
	}

	inline void CMDIFrame::UpdateCheckMarks()
	{
		if ((GetActiveMDIChild()) && GetActiveMDIChild()->m_hChildMenu)
		{
			HMENU hMenu = GetActiveMDIChild()->m_hChildMenu;

			UINT uCheck = GetToolBar().IsWindowVisible()? MF_CHECKED : MF_UNCHECKED;
			::CheckMenuItem(hMenu, IDW_VIEW_TOOLBAR, uCheck);

			uCheck = GetStatusBar().IsWindowVisible()? MF_CHECKED : MF_UNCHECKED;
			::CheckMenuItem (hMenu, IDW_VIEW_STATUSBAR, uCheck);
		}
	}

	inline void CMDIFrame::UpdateFrameMenu(HMENU hMenu)
	{
		int nMenuItems = GetMenuItemCount(hMenu);
		if (nMenuItems > 0)
		{
			// The Window menu is typically second from the right
			int nWindowItem = MAX (nMenuItems -2, 0);
			HMENU hMenuWindow = ::GetSubMenu (hMenu, nWindowItem);

			if (hMenuWindow)
			{
				if (IsMenuBarUsed())
				{
					AppendMDIMenu(hMenuWindow);
					GetMenuBar().SetMenu(hMenu);
				}
				else
				{
					GetView()->SendMessage (WM_MDISETMENU, (WPARAM) hMenu, (LPARAM)hMenuWindow);
					DrawMenuBar();
				}
			}
		}
		UpdateCheckMarks();
	}

	inline LRESULT CMDIFrame::WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam)
	{
		switch (uMsg)
		{
		case WM_CLOSE:
			OnClose();
			return 0;

		case WM_WINDOWPOSCHANGED:
			// MDI Child or MDI frame has been resized
			OnWindowPosChanged();
			break; // Continue with default processing

		} // switch uMsg
		return CFrame::WndProcDefault(uMsg, wParam, lParam);
	}

	inline HWND CMDIFrame::CMDIClient::Create(CWnd* pParent)
	{
		assert(pParent != 0);

		CLIENTCREATESTRUCT clientcreate ;
		clientcreate.hWindowMenu  = m_hWnd;
		clientcreate.idFirstChild = IDW_FIRSTCHILD ;
		DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | MDIS_ALLCHILDSTYLES;

		// Create the view window
		CreateEx(WS_EX_CLIENTEDGE, _T("MDICLient"), TEXT(""), dwStyle, 0, 0, 0, 0, pParent, NULL, (PSTR) &clientcreate);

		return m_hWnd;
	}

	inline LRESULT CMDIFrame::CMDIClient::WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
	{
		switch (uMsg)
		{
		case WM_MDIDESTROY:
			{
				// Do default processing first
				CallWindowProc(GetPrevWindowProc(), uMsg, wParam, lParam);

				// Now remove MDI child
				GetMDIFrame()->RemoveMDIChild((HWND) wParam);
			}
			return 0; // Discard message

		case WM_MDISETMENU:
			{
				if (GetMDIFrame()->IsMenuBarUsed())
				{
					return 0L;
				}
			}
			break;

		case WM_MDIACTIVATE:
			{
				// Suppress redraw to avoid flicker when activating maximised MDI children
				SendMessage(WM_SETREDRAW, FALSE, 0L);
				LRESULT lr = CallWindowProc(GetPrevWindowProc(), WM_MDIACTIVATE, wParam, lParam);
				SendMessage(WM_SETREDRAW, TRUE, 0L);
				RedrawWindow(0, 0, RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);

				return lr;
			}
		}
		return CWnd::WndProcDefault(uMsg, wParam, lParam);
	}


	/////////////////////////////////////
	//Definitions for the CMDIChild class
	//
	inline CMDIChild::CMDIChild() : m_pView(NULL), m_hChildMenu(NULL)
	{
		// Set the MDI Child's menu and accelerator in the constructor, like this ...
		//   HMENU hChildMenu = LoadMenu(GetApp()->GetResourceHandle(), _T("MdiMenuView"));
		//   HACCEL hChildAccel = LoadAccelerators(GetApp()->GetResourceHandle(), _T("MDIAccelView"));
		//   SetHandles(hChildMenu, hChildAccel);
	}

	inline CMDIChild::~CMDIChild()
	{
		if (IsWindow())
			GetParent()->SendMessage(WM_MDIDESTROY, (WPARAM)m_hWnd, 0L);

		if (m_hChildMenu)
			::DestroyMenu(m_hChildMenu);
	}

	inline HWND CMDIChild::Create(CWnd* pParent /*= NULL*/)
	// We create the MDI child window and then maximize if required.
	// This technique avoids unnecessary flicker when creating maximized MDI children.
	{
		//Call PreCreate in case its overloaded
		PreCreate(*m_pcs);

		//Determine if the window should be created maximized
		BOOL bMax = FALSE;
		pParent->SendMessage(WM_MDIGETACTIVE, 0L, (LPARAM)&bMax);
		bMax = bMax | (m_pcs->style & WS_MAXIMIZE);

		// Set the Window Class Name
		TCHAR szClassName[MAX_STRING_SIZE + 1] = _T("Win32++ MDI Child");
		if (m_pcs->lpszClass)
			lstrcpyn(szClassName, m_pcs->lpszClass, MAX_STRING_SIZE);

		// Set the window style
		DWORD dwStyle;
		dwStyle = m_pcs->style & ~WS_MAXIMIZE;
		dwStyle |= WS_VISIBLE | WS_OVERLAPPEDWINDOW ;

		// Set window size and position
		int x = CW_USEDEFAULT;
		int	y = CW_USEDEFAULT;
		int cx = CW_USEDEFAULT;
		int cy = CW_USEDEFAULT;
		if(m_pcs->cx && m_pcs->cy)
		{
			x = m_pcs->x;
			y = m_pcs->y;
			cx = m_pcs->cx;
			cy = m_pcs->cy;
		}

		// Set the extended style
		DWORD dwExStyle = m_pcs->dwExStyle | WS_EX_MDICHILD;

		// Turn off redraw while creating the window
		pParent->SendMessage(WM_SETREDRAW, FALSE, 0L);

		// Create the window
		if (!CreateEx(dwExStyle, szClassName, m_pcs->lpszName, dwStyle, x, y,
			cx, cy, pParent, FromHandle(m_pcs->hMenu), m_pcs->lpCreateParams))
			throw CWinException(_T("CMDIChild::Create ... CreateEx failed"));

		if (bMax)
			ShowWindow(SW_MAXIMIZE);

		// Turn redraw back on
		pParent->SendMessage(WM_SETREDRAW, TRUE, 0L);
		pParent->RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN);

		// Ensure bits revealed by round corners (XP themes) are redrawn
		SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_FRAMECHANGED);

		if (m_hChildMenu)
			GetMDIFrame()->UpdateFrameMenu(m_hChildMenu);
		if (m_hChildAccel)
			GetApp()->SetAccelerators(m_hChildAccel, this);

		return m_hWnd;
	}

	inline CMDIFrame* CMDIChild::GetMDIFrame() const
	{
		CMDIFrame* pMDIFrame = (CMDIFrame*)GetParent()->GetParent();
		assert(dynamic_cast<CMDIFrame*>(pMDIFrame));
		return pMDIFrame;
	}

	inline LRESULT CMDIChild::FinalWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
	{
		return ::DefMDIChildProc(m_hWnd, uMsg, wParam, lParam);
	}

	inline void CMDIChild::MDIActivate() const
	{
		GetParent()->SendMessage(WM_MDIACTIVATE, (WPARAM)m_hWnd, 0L);
	}

	inline void CMDIChild::MDIDestroy() const
	{
		GetParent()->SendMessage(WM_MDIDESTROY, (WPARAM)m_hWnd, 0L);
	}

	inline void CMDIChild::MDIMaximize() const
	{
		GetParent()->SendMessage(WM_MDIMAXIMIZE, (WPARAM)m_hWnd, 0L);
	}

	inline void CMDIChild::MDIRestore() const
	{
		GetParent()->SendMessage(WM_MDIRESTORE, (WPARAM)m_hWnd, 0L);
	}

	inline void CMDIChild::OnCreate()
	{
		// Create the view window
		assert(GetView());			// Use SetView in CMDIChild's constructor to set the view window
		GetView()->Create(this);
		RecalcLayout();
	}

	inline void CMDIChild::RecalcLayout()
	{
		// Resize the View window
		CRect rc = GetClientRect();
		m_pView->SetWindowPos( NULL, rc.left, rc.top, rc.Width(), rc.Height(), SWP_SHOWWINDOW );
	}

	inline void CMDIChild::SetHandles(HMENU hMenu, HACCEL hAccel)
	{
		m_hChildMenu = hMenu;
		m_hChildAccel = hAccel;

		// Note: It is valid to call SetChildMenu before the window is created
		if (IsWindow())
		{
			CWnd* pWnd = GetMDIFrame()->GetActiveMDIChild();
			if (pWnd == this)
			{
				if (m_hChildMenu)
					GetMDIFrame()->UpdateFrameMenu(m_hChildMenu);

				if (m_hChildAccel)
					GetApp()->SetAccelerators(m_hChildAccel, GetMDIFrame());
			}
		}
	}

	inline void CMDIChild::SetView(CWnd& wndView)
	// Sets or changes the View window displayed within the frame
	{
		if (m_pView != &wndView)
		{
			// Destroy the existing view window (if any)
			if (m_pView) m_pView->Destroy();

			// Assign the view window
			m_pView = &wndView;

			if (m_hWnd)
			{
				// The frame is already created, so create and position the new view too
				assert(GetView());			// Use SetView in CMDIChild's constructor to set the view window
				GetView()->Create(this);
				RecalcLayout();
			}
		}
	}

	inline LRESULT CMDIChild::WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam)
	{
		switch (uMsg)
		{
		case WM_MDIACTIVATE:
			{
				// This child is being activated
				if (lParam == (LPARAM) m_hWnd)
				{
					GetMDIFrame()->m_hActiveMDIChild = m_hWnd;
					// Set the menu to child default menu
					if (m_hChildMenu)
						GetMDIFrame()->UpdateFrameMenu(m_hChildMenu);
					if (m_hChildAccel)
						GetApp()->SetAccelerators(m_hChildAccel, this);
				}

				// No child is being activated
				if (0 == lParam)
				{
					GetMDIFrame()->m_hActiveMDIChild = NULL;
					// Set the menu to frame's original menu
					GetMDIFrame()->UpdateFrameMenu(GetMDIFrame()->GetFrameMenu());
					GetApp()->SetAccelerators(GetMDIFrame()->GetFrameAccel(), this);
				}
			}
			return 0L ;

		case WM_WINDOWPOSCHANGED:
			{
				RecalcLayout();
				break;
			}
		}
		return CWnd::WndProcDefault(uMsg, wParam, lParam);
	}


} // namespace Win32xx

#endif // _WIN32XX_MDI_H_