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


////////////////////////////////////////////////////////
// frame.h
//  Declaration of the CFrame and CMenuBar classes

// The classes declared in this file support SDI (Single Document Interface)
// frames on Win32/Win64 operating systems (not Windows CE). For Windows CE,
// use wceframe.h instead. SDI frames are a simple frame which supports a
// single view window. Refer to mdi.h for frames that support several
// child windows.

// CFrame also includes each of the following classes as members:
// * CReBar for managing the frame's rebar control.
// * CMenuBar for managing the menu inside the rebar.
// * CToolBar for managing the frame's toolbar.
// * CStatusBar for managing the frame's status bar.
// In each case these members are exposed by a GetXXX function, allowing
// them to be accessed or sent messages.

// CFrame is responsible for creating a "frame" window. This window has a
// menu and and several child windows, including a toolbar (usualy hosted
// within a rebar), a status bar, and a view positioned over the frame
// window's non-client area. The "view" window is a seperate CWnd object
// assigned to the frame with the SetView function.

// When compiling an application with these classes, it will need to be linked
// with Comctl32.lib.

// To create a SDI frame application, inherit a CMainFrame class from CFrame.
// Use the Frame sample application as the starting point for your own frame
// applications.
// Refer to the Notepad and Scribble samples for examples on how to use these
// classes to create a frame application.


#ifndef _WIN32XX_FRAME_H_
#define _WIN32XX_FRAME_H_

#include "wincore.h"
#include "dialog.h"
#include "gdi.h"
#include "statusbar.h"
#include "toolbar.h"
#include "rebar.h"
#include "default_resource.h"

#ifndef RBN_MINMAX
  #define RBN_MINMAX (RBN_FIRST - 21)
#endif


namespace Win32xx
{

	////////////////////////////////////////////////
	// Declarations for structures for themes
	//
	struct MenuTheme
	{
		BOOL UseThemes;			// TRUE if themes are used
		COLORREF clrHot1;		// Colour 1 for top menu. Color of selected menu item
		COLORREF clrHot2;		// Colour 2 for top menu. Color of checkbox
		COLORREF clrPressed1;	// Colour 1 for pressed top menu and side bar
		COLORREF clrPressed2;	// Colour 2 for pressed top menu and side bar
		COLORREF clrOutline;	// Colour for border outline
	};


	// Forward declaration of CFrame. Its defined later.
	class CFrame;


	////////////////////////////////////
	// Declaration of the CMenuBar class
	//
	class CMenuBar : public CToolBar
	{
		friend class CFrame;

	public:
		CMenuBar();
		virtual ~CMenuBar();
		virtual void SetMenu(HMENU hMenu);
		virtual void SetMenuBarTheme(MenuTheme& Theme);

		HMENU GetMenu() const {return m_hTopMenu;}
		MenuTheme& GetMenuBarTheme() {return m_ThemeMenu;}

	protected:
	//Overridables
		virtual void OnCreate();
		virtual LRESULT OnCustomDraw(NMHDR* pNMHDR);
		virtual void OnKeyDown(WPARAM wParam, LPARAM lParam);
		virtual void OnLButtonDown(WPARAM wParam, LPARAM lParam);
		virtual void OnLButtonUp(WPARAM wParam, LPARAM lParam);
		virtual void OnMenuChar(WPARAM wParam, LPARAM lParam);
		virtual BOOL OnMenuInput(UINT uMsg, WPARAM wParam, LPARAM lParam);
		virtual void OnMouseLeave();
		virtual void OnMouseMove(WPARAM wParam, LPARAM lParam);
		virtual LRESULT OnNotifyReflect(WPARAM wParam, LPARAM lParam);
		virtual void OnSysCommand(WPARAM wParam, LPARAM lParam);
		virtual void OnWindowPosChanged();
		virtual void PreCreate(CREATESTRUCT &cs);
		virtual void PreRegisterClass(WNDCLASS &wc);
		virtual LRESULT WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam);

	private:
		CMenuBar(const CMenuBar&);				// Disable copy construction
		CMenuBar& operator = (const CMenuBar&); // Disable assignment operator
		void DoAltKey(WORD KeyCode);
		void DoPopupMenu();
		void DrawAllMDIButtons(CDC& DrawDC);
		void DrawMDIButton(CDC& DrawDC, int iButton, UINT uState);
		void ExitMenu();
		HWND GetActiveMDIChild();
		void GrabFocus();
		BOOL IsMDIChildMaxed() const;
		BOOL IsMDIFrame() const;
		void ReleaseFocus();
		void SetHotItem(int nHot);
		static LRESULT CALLBACK StaticMsgHook(int nCode, WPARAM wParam, LPARAM lParam);

		enum MDIButtonType
		{
			MDI_MIN = 0,
			MDI_RESTORE = 1,
			MDI_CLOSE = 2,
		};

		BOOL  m_bExitAfter;		// Exit after Popup menu ends
		BOOL  m_bKeyMode;		// keyboard navigation mode
		BOOL  m_bMenuActive;	// popup menu active
		BOOL  m_bSelPopup;		// a popup (cascade) menu is selected
		HMENU m_hPopupMenu;		// handle to the popup menu
		HMENU m_hSelMenu;		// handle to the casceded popup menu
		HMENU m_hTopMenu;		// handle to the top level menu
		HWND  m_hPrevFocus;		// handle to window which had focus
		CRect m_MDIRect[3];		// array of CRect for MDI buttons
		int   m_nHotItem;		// hot item
		int   m_nMDIButton;		// the MDI button (MDIButtonType) pressed
		CPoint m_OldMousePos;	// old Mouse position
		MenuTheme m_ThemeMenu;	// Theme structure
		CFrame* m_pFrame;       // Pointer to the frame

	};  // class CMenuBar



	//////////////////////////////////
	// Declaration of the CFrame class
	//
	class CFrame : public CWnd
	{
		friend class CMenuBar;

		struct ItemData
		// Each Dropdown menu item has this data
		{
			HMENU hMenu;
			UINT  nPos;
			UINT  fType;
			std::vector<TCHAR> vItemText;
			HMENU hSubMenu;

			ItemData() : hMenu(0), nPos(0), fType(0), hSubMenu(0) { vItemText.assign(MAX_MENU_STRING, _T('\0')); }
			LPTSTR GetItemText() {return &vItemText[0];}
		};

		typedef Shared_Ptr<ItemData> ItemDataPtr;

	public:
		CFrame();
		virtual ~CFrame();

		// Override these functions as required
		virtual void AdjustFrameRect(RECT rcView) const;
		virtual CRect GetViewRect() const;
		virtual BOOL IsMDIFrame() const { return FALSE; }
		virtual void SetStatusIndicators();
		virtual void SetStatusText();
		virtual void RecalcLayout();
		virtual MenuTheme& GetMenuTheme() const			{ return (MenuTheme&) m_ThemeMenu; }
		virtual ReBarTheme& GetReBarTheme()	const		{ return (ReBarTheme&)GetReBar().GetReBarTheme(); }
		virtual ToolBarTheme& GetToolBarTheme() const	{ return (ToolBarTheme&)GetToolBar().GetToolBarTheme(); }

		// Virtual Attributes
		// If you need to modify the default behaviour of the menubar, rebar,
		// statusbar or toolbar, inherit from those classes, and override
		// the following attribute functions.
		virtual CMenuBar& GetMenuBar() const		{ return (CMenuBar&)m_MenuBar; }
		virtual CReBar& GetReBar() const			{ return (CReBar&)m_ReBar; }
		virtual CStatusBar& GetStatusBar() const	{ return (CStatusBar&)m_StatusBar; }
		virtual CToolBar& GetToolBar() const		{ return (CToolBar&)m_ToolBar; }

		// These functions aren't virtual, and shouldn't be overridden
		HACCEL GetFrameAccel() const				{ return m_hAccel; }
		CMenu& GetFrameMenu() const					{ return (CMenu&)m_Menu; }
		std::vector<tString> GetMRUEntries() const	{ return m_vMRUEntries; }
		tString GetRegistryKeyName() const			{ return m_tsKeyName; }
		CWnd* GetView() const						{ return m_pView; }
		tString GetMRUEntry(UINT nIndex);
		void SetFrameMenu(INT ID_MENU);
		void SetFrameMenu(HMENU hMenu);
		void SetMenuTheme(MenuTheme& Theme);
		void SetView(CWnd& wndView);
		BOOL IsMenuBarUsed() const		{ return (GetMenuBar() != 0); }
		BOOL IsReBarSupported() const	{ return (GetComCtlVersion() >= 470); }
		BOOL IsReBarUsed() const		{ return (GetReBar() != 0); }

	protected:
		// Override these functions as required
		virtual BOOL AddMenuIcon(int nID_MenuItem, HICON hIcon, int cx = 16, int cy = 16);
		virtual UINT AddMenuIcons(const std::vector<UINT>& MenuData, COLORREF crMask, UINT ToolBarID, UINT ToolBarDisabledID);
		virtual void AddMenuBarBand();
		virtual void AddMRUEntry(LPCTSTR szMRUEntry);
		virtual void AddToolBarBand(CToolBar& TB, DWORD dwStyle, UINT nID);
		virtual void AddToolBarButton(UINT nID, BOOL bEnabled = TRUE, LPCTSTR szText = 0);
		virtual void CreateToolBar();
		virtual void DrawCheckmark(LPDRAWITEMSTRUCT pdis, CDC& DrawDC);
		virtual void DrawMenuIcon(LPDRAWITEMSTRUCT pdis, CDC& DrawDC, BOOL bDisabled);
		virtual void DrawMenuText(CDC& DrawDC, LPCTSTR ItemText, CRect& rc, COLORREF colorText);
		virtual int  GetMenuItemPos(HMENU hMenu, LPCTSTR szItem);
		virtual BOOL LoadRegistrySettings(LPCTSTR szKeyName);
		virtual BOOL LoadRegistryMRUSettings(UINT nMaxMRU = 0);
		virtual void OnActivate(WPARAM wParam, LPARAM lParam);
		virtual void OnClose();
		virtual void OnCreate();
		virtual void OnDestroy();
		virtual LRESULT OnDrawItem(WPARAM wParam, LPARAM lParam);
		virtual void OnExitMenuLoop();
		virtual void OnHelp();
		virtual void OnInitMenuPopup(WPARAM wParam, LPARAM lParam);
		virtual LRESULT OnMeasureItem(WPARAM wParam, LPARAM lParam);
		virtual LRESULT OnMenuChar(WPARAM wParam, LPARAM lParam);
		virtual void OnMenuSelect(WPARAM wParam, LPARAM lParam);
		virtual LRESULT OnNotify(WPARAM wParam, LPARAM lParam);
		virtual void OnSetFocus();
		virtual void OnSysColorChange();
		virtual LRESULT OnSysCommand(WPARAM wParam, LPARAM lParam);
		virtual	void OnTimer(WPARAM wParam);
		virtual void OnViewStatusBar();
		virtual void OnViewToolBar();
		virtual void PreCreate(CREATESTRUCT& cs);
		virtual void PreRegisterClass(WNDCLASS &wc);
		virtual void RemoveMRUEntry(LPCTSTR szMRUEntry);
		virtual BOOL SaveRegistrySettings();
		virtual void SetMenuBarBandSize();
		virtual UINT SetMenuIcons(const std::vector<UINT>& MenuData, COLORREF crMask, UINT ToolBarID, UINT ToolBarDisabledID);
		virtual void SetupToolBar();
		virtual void SetTheme();
		virtual void SetToolBarImages(COLORREF crMask, UINT ToolBarID, UINT ToolBarHotID, UINT ToolBarDisabledID);
		virtual void ShowMenu(BOOL bShow);
		virtual void ShowStatusBar(BOOL bShow);
		virtual void ShowToolBar(BOOL bShow);
		virtual void UpdateMRUMenu();
		virtual LRESULT WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam);

		enum Constants
		{
			ID_STATUS_TIMER = 1,
			POST_TEXT_GAP   = 16,			// for owner draw menu item
		};

		tString m_tsStatusText;				// TCHAR std::string for status text
        BOOL m_bShowIndicatorStatus;		// set to TRUE to see indicators in status bar
		BOOL m_bShowMenuStatus;				// set to TRUE to see menu and toolbar updates in status bar
		BOOL m_bUseReBar;					// set to TRUE if ReBars are to be used
		BOOL m_bUseThemes;					// set to TRUE if themes are to be used
		BOOL m_bUpdateTheme;				// set to TRUE to run SetThemes when theme changes
		BOOL m_bUseToolBar;					// set to TRUE if the toolbar is used
		BOOL m_bUseCustomDraw;				// set to TRUE to perform custom drawing on menu items
		BOOL m_bShowStatusBar;				// A flag to indicate if the StatusBar should be displayed
		BOOL m_bShowToolBar;				// A flag to indicate if the ToolBar should be displayed
		MenuTheme m_ThemeMenu;				// Theme structure for popup menus
		HIMAGELIST m_himlMenu;				// Imagelist of menu icons
		HIMAGELIST m_himlMenuDis;			// Imagelist of disabled menu icons

	private:
		CFrame(const CFrame&);				// Disable copy construction
		CFrame& operator = (const CFrame&); // Disable assignment operator
		void LoadCommonControls();

		std::vector<ItemDataPtr> m_vMenuItemData;// vector of ItemData pointers
		std::vector<UINT> m_vMenuIcons;		// vector of menu icon resource IDs
		std::vector<tString> m_vMRUEntries;	// Vector of tStrings for MRU entires
		CDialog m_AboutDialog;				// Help about dialog
		CMenuBar m_MenuBar;					// CMenuBar object
		CReBar m_ReBar;						// CReBar object
		CStatusBar m_StatusBar;				// CStatusBar object
		CToolBar m_ToolBar;					// CToolBar object
		CMenu m_Menu;						// handle to the frame menu
		HACCEL m_hAccel;					// handle to the frame's accelerator table
		CWnd* m_pView;						// pointer to the View CWnd object
		LPCTSTR m_OldStatus[3];				// Array of TCHAR pointers;
		tString m_tsKeyName;				// TCHAR std::string for Registry key name
		tString m_tsTooltip;				// TCHAR std::string for tool tips
		UINT m_nMaxMRU;						// maximum number of MRU entries
		CRect m_rcPosition;					// CRect of the starting window position
		HWND m_hOldFocus;					// The window which had focus prior to the app'a deactivation
		int m_nOldID;						// The previous ToolBar ID displayed in the statusbar

	};  // class CFrame

}


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


namespace Win32xx
{

	/////////////////////////////////////
	// Definitions for the CMenuBar class
	//
	inline CMenuBar::CMenuBar()
	{
		m_bExitAfter	= FALSE;
		m_hTopMenu		= NULL;
		m_nHotItem		= -1;
		m_bSelPopup		= FALSE;
		m_hSelMenu		= NULL;
		m_bMenuActive	= FALSE;
		m_bKeyMode		= FALSE;
		m_hPrevFocus	= NULL;
		m_nMDIButton    = 0;
		m_hPopupMenu	= 0;

		ZeroMemory(&m_ThemeMenu, sizeof(MenuTheme));
	}

	inline CMenuBar::~CMenuBar()
	{
	}

	inline void CMenuBar::DoAltKey(WORD KeyCode)
	{
		//Handle key pressed with Alt held down
		UINT ID;
		if (SendMessage(TB_MAPACCELERATOR, KeyCode, (LPARAM) &ID))
		{
			GrabFocus();
			m_bKeyMode = TRUE;
			SetHotItem(ID);
			m_bMenuActive = TRUE;
			PostMessage(UWM_POPUPMENU, 0L, 0L);
		}
		else
			::MessageBeep(MB_OK);
	}

	inline void CMenuBar::DoPopupMenu()
	{
		if (m_bKeyMode)
			// Simulate a down arrow key press
			PostMessage(WM_KEYDOWN, VK_DOWN, 0L);

		m_bKeyMode = FALSE;
		m_bExitAfter = FALSE;
		m_OldMousePos = GetCursorPos();

		HWND hMaxMDIChild = NULL;
		if (IsMDIChildMaxed())
			hMaxMDIChild = GetActiveMDIChild();

		// Load the submenu
		int nMaxedOffset = IsMDIChildMaxed()? 1:0;
		m_hPopupMenu = ::GetSubMenu(m_hTopMenu, m_nHotItem - nMaxedOffset);
		if (IsMDIChildMaxed() && (0 == m_nHotItem) )
			m_hPopupMenu = ::GetSystemMenu(hMaxMDIChild, FALSE);

        // Retrieve the bounding rectangle for the toolbar button
		CRect rc = GetItemRect(m_nHotItem);

		// convert rectangle to desktop coordinates
		ClientToScreen(rc);

		// Position popup above toolbar if it won't fit below
		TPMPARAMS tpm;
		tpm.cbSize = sizeof(TPMPARAMS);
		tpm.rcExclude = rc;

		// Set the hot button
		SendMessage(TB_SETHOTITEM, m_nHotItem, 0L);
		SendMessage(TB_PRESSBUTTON, m_nHotItem, MAKELONG(TRUE, 0));

		m_bSelPopup = FALSE;
		m_hSelMenu = NULL;
		m_bMenuActive = TRUE;

		// We hook mouse input to process mouse and keyboard input during
		//  the popup menu. Messages are sent to StaticMsgHook.

		// Remove any remaining hook first
		TLSData* pTLSData = (TLSData*)::TlsGetValue(GetApp()->GetTlsIndex());
		pTLSData->pMenuBar = this;
		if (pTLSData->hHook != NULL)
			::UnhookWindowsHookEx(pTLSData->hHook);

		// Hook messages about to be processed by the shortcut menu
		pTLSData->hHook = ::SetWindowsHookEx(WH_MSGFILTER, (HOOKPROC)StaticMsgHook, NULL, ::GetCurrentThreadId());

		// Display the shortcut menu
		BOOL bRightToLeft = FALSE;

#if defined(WINVER) && defined (WS_EX_LAYOUTRTL) && (WINVER >= 0x0500)
		bRightToLeft = ((GetAncestor()->GetWindowLongPtr(GWL_EXSTYLE)) & WS_EX_LAYOUTRTL);
#endif

		int xPos = bRightToLeft? rc.right : rc.left;
		UINT nID = ::TrackPopupMenuEx(m_hPopupMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_VERTICAL,
			xPos, rc.bottom, m_hWnd, &tpm);

		// We get here once the TrackPopupMenuEx has ended
		m_bMenuActive = FALSE;

		// Remove the message hook
		::UnhookWindowsHookEx(pTLSData->hHook);
		pTLSData->hHook = NULL;

		// Process MDI Child system menu
		if (IsMDIChildMaxed())
		{
			if (::GetSystemMenu(hMaxMDIChild, FALSE) == m_hPopupMenu )
			{
				if (nID)
					::SendMessage(hMaxMDIChild, WM_SYSCOMMAND, nID, 0L);
			}
		}

		// Resestablish Focus
		if (m_bKeyMode)
			GrabFocus();
	}

	inline void CMenuBar::DrawAllMDIButtons(CDC& DrawDC)
	{
		if (!IsMDIFrame())
			return;

		if (IsMDIChildMaxed())
		{
			int cx = GetSystemMetrics(SM_CXSMICON);
			int cy = GetSystemMetrics(SM_CYSMICON);
			CRect rc = GetClientRect();
			int gap = 4;
			rc.right -= gap;

			// Assign values to each element of the CRect array
			for (int i = 0 ; i < 3 ; ++i)
			{
				int left = rc.right - (i+1)*cx - gap*(i+1);
				int top = rc.bottom/2 - cy/2;
				int right = rc.right - i*cx - gap*(i+1);
				int bottom = rc.bottom/2 + cy/2;
				::SetRect(&m_MDIRect[2 - i], left, top, right, bottom);
			}

			// Hide the MDI button if it won't fit
			for (int k = 0 ; k <= 2 ; ++k)
			{

				if (m_MDIRect[k].left < GetMaxSize().cx)
				{
					::SetRectEmpty(&m_MDIRect[k]);
				}
			}

			DrawMDIButton(DrawDC, MDI_MIN, 0);
			DrawMDIButton(DrawDC, MDI_RESTORE, 0);
			DrawMDIButton(DrawDC, MDI_CLOSE, 0);
		}
	}

	inline void CMenuBar::DrawMDIButton(CDC& DrawDC, int iButton, UINT uState)
	{
		if (!IsRectEmpty(&m_MDIRect[iButton]))
		{
			switch (uState)
			{
			case 0:
				{
					// Draw a grey outline
					DrawDC.CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNFACE));
					DrawDC.MoveTo(m_MDIRect[iButton].left, m_MDIRect[iButton].bottom);
					DrawDC.LineTo(m_MDIRect[iButton].right, m_MDIRect[iButton].bottom);
					DrawDC.LineTo(m_MDIRect[iButton].right, m_MDIRect[iButton].top);
					DrawDC.LineTo(m_MDIRect[iButton].left, m_MDIRect[iButton].top);
					DrawDC.LineTo(m_MDIRect[iButton].left, m_MDIRect[iButton].bottom);
				}
				break;
			case 1:
				{
					// Draw outline, white at top, black on bottom
					DrawDC.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
					DrawDC.MoveTo(m_MDIRect[iButton].left, m_MDIRect[iButton].bottom);
					DrawDC.LineTo(m_MDIRect[iButton].right, m_MDIRect[iButton].bottom);
					DrawDC.LineTo(m_MDIRect[iButton].right, m_MDIRect[iButton].top);
					DrawDC.CreatePen(PS_SOLID, 1, RGB(255, 255, 255));
					DrawDC.LineTo(m_MDIRect[iButton].left, m_MDIRect[iButton].top);
					DrawDC.LineTo(m_MDIRect[iButton].left, m_MDIRect[iButton].bottom);
				}

				break;
			case 2:
				{
					// Draw outline, black on top, white on bottom
					DrawDC.CreatePen(PS_SOLID, 1, RGB(255, 255, 255));
					DrawDC.MoveTo(m_MDIRect[iButton].left, m_MDIRect[iButton].bottom);
					DrawDC.LineTo(m_MDIRect[iButton].right, m_MDIRect[iButton].bottom);
					DrawDC.LineTo(m_MDIRect[iButton].right, m_MDIRect[iButton].top);
					DrawDC.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
					DrawDC.LineTo(m_MDIRect[iButton].left, m_MDIRect[iButton].top);
					DrawDC.LineTo(m_MDIRect[iButton].left, m_MDIRect[iButton].bottom);
				}
				break;
			}

			DrawDC.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));

			switch (iButton)
			{
			case MDI_MIN:
				// Manually Draw Minimise button
				DrawDC.MoveTo(m_MDIRect[0].left + 4, m_MDIRect[0].bottom -4);
				DrawDC.LineTo(m_MDIRect[0].right - 4, m_MDIRect[0].bottom - 4);

				DrawDC.MoveTo(m_MDIRect[0].left + 4, m_MDIRect[0].bottom -5);
				DrawDC.LineTo(m_MDIRect[0].right - 4, m_MDIRect[0].bottom - 5);
				break;
			case MDI_RESTORE:
				// Manually Draw Restore Button
				DrawDC.MoveTo(m_MDIRect[1].left + 3, m_MDIRect[1].top + 7);
				DrawDC.LineTo(m_MDIRect[1].left + 3, m_MDIRect[1].bottom -4);
				DrawDC.LineTo(m_MDIRect[1].right - 6, m_MDIRect[1].bottom -4);
				DrawDC.LineTo(m_MDIRect[1].right - 6, m_MDIRect[1].top + 7);
				DrawDC.LineTo(m_MDIRect[1].left + 3, m_MDIRect[1].top + 7);

				DrawDC.MoveTo(m_MDIRect[1].left + 3, m_MDIRect[1].top + 8);
				DrawDC.LineTo(m_MDIRect[1].right - 6, m_MDIRect[1].top + 8);

				DrawDC.MoveTo(m_MDIRect[1].left + 5, m_MDIRect[1].top + 7);
				DrawDC.LineTo(m_MDIRect[1].left + 5, m_MDIRect[1].top + 4);
				DrawDC.LineTo(m_MDIRect[1].right - 4, m_MDIRect[1].top + 4);
				DrawDC.LineTo(m_MDIRect[1].right - 4, m_MDIRect[1].bottom -6);
				DrawDC.LineTo(m_MDIRect[1].right - 6, m_MDIRect[1].bottom -6);

				DrawDC.MoveTo(m_MDIRect[1].left + 5, m_MDIRect[1].top + 5);
				DrawDC.LineTo(m_MDIRect[1].right - 4, m_MDIRect[1].top + 5);
				break;
			case MDI_CLOSE:
				// Manually Draw Close Button
				DrawDC.MoveTo(m_MDIRect[2].left + 4, m_MDIRect[2].top +5);
				DrawDC.LineTo(m_MDIRect[2].right - 4, m_MDIRect[2].bottom -3);

				DrawDC.MoveTo(m_MDIRect[2].left + 5, m_MDIRect[2].top +5);
				DrawDC.LineTo(m_MDIRect[2].right - 4, m_MDIRect[2].bottom -4);

				DrawDC.MoveTo(m_MDIRect[2].left + 4, m_MDIRect[2].top +6);
				DrawDC.LineTo(m_MDIRect[2].right - 5, m_MDIRect[2].bottom -3);

				DrawDC.MoveTo(m_MDIRect[2].right -5, m_MDIRect[2].top +5);
				DrawDC.LineTo(m_MDIRect[2].left + 3, m_MDIRect[2].bottom -3);

				DrawDC.MoveTo(m_MDIRect[2].right -5, m_MDIRect[2].top +6);
				DrawDC.LineTo(m_MDIRect[2].left + 4, m_MDIRect[2].bottom -3);

				DrawDC.MoveTo(m_MDIRect[2].right -6, m_MDIRect[2].top +5);
				DrawDC.LineTo(m_MDIRect[2].left + 3, m_MDIRect[2].bottom -4);
				break;
			}
		}
	}

	inline void CMenuBar::ExitMenu()
	{
		ReleaseFocus();
		m_bKeyMode = FALSE;
		m_bMenuActive = FALSE;
		SendMessage(TB_PRESSBUTTON, m_nHotItem, (LPARAM) MAKELONG (FALSE, 0));
		SetHotItem(-1);

		CPoint pt = GetCursorPos();
		ScreenToClient(pt);

		// Update mouse mouse position for hot tracking
		SendMessage(WM_MOUSEMOVE, 0L, MAKELONG(pt.x, pt.y));
	}

	inline HWND CMenuBar::GetActiveMDIChild()
	{
		HWND hwndMDIChild = NULL;
		if (IsMDIFrame())
		{
			hwndMDIChild = (HWND)::SendMessage(m_pFrame->GetView()->GetHwnd(), WM_MDIGETACTIVE, 0L, 0L);
		}

		return hwndMDIChild;
	}

	inline void CMenuBar::GrabFocus()
	{
		if (::GetFocus() != m_hWnd)
			m_hPrevFocus = ::SetFocus(m_hWnd);
		::SetCapture(m_hWnd);
		::SetCursor(::LoadCursor(NULL, IDC_ARROW));
	}

	inline BOOL CMenuBar::IsMDIChildMaxed() const
	{
		BOOL bMaxed = FALSE;

		if (IsMDIFrame() && m_pFrame->GetView()->IsWindow())
		{
			m_pFrame->GetView()->SendMessage(WM_MDIGETACTIVE, 0L, (LPARAM)&bMaxed);
		}

		return bMaxed;
	}

	inline BOOL CMenuBar::IsMDIFrame() const
	{
		return (m_pFrame->IsMDIFrame());	
	}

	inline void CMenuBar::OnMenuChar(WPARAM wParam, LPARAM lParam)
	{
		UNREFERENCED_PARAMETER(lParam);

		if (!m_bMenuActive)
			DoAltKey(LOWORD(wParam));
	}

	inline void CMenuBar::OnCreate()
	{
		// We must send this message before sending the TB_ADDBITMAP or TB_ADDBUTTONS message
		SendMessage(TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0L);

		m_pFrame = (CFrame*)GetAncestor();
		assert(m_pFrame);
	}

	inline LRESULT CMenuBar::OnCustomDraw(NMHDR* pNMHDR)
	// CustomDraw is used to render the MenuBar's toolbar buttons
	{
		if (m_ThemeMenu.UseThemes)
		{
			LPNMTBCUSTOMDRAW lpNMCustomDraw = (LPNMTBCUSTOMDRAW)pNMHDR;

			switch (lpNMCustomDraw->nmcd.dwDrawStage)
			{
			// Begin paint cycle
			case CDDS_PREPAINT:
				// Send NM_CUSTOMDRAW item draw, and post-paint notification messages.
				return CDRF_NOTIFYITEMDRAW | CDRF_NOTIFYPOSTPAINT ;

			// An item is about to be drawn
			case CDDS_ITEMPREPAINT:
				{
					CDC* pDrawDC = FromHandle(lpNMCustomDraw->nmcd.hdc);
					CRect rcRect = lpNMCustomDraw->nmcd.rc;
					int nState = lpNMCustomDraw->nmcd.uItemState;
					DWORD dwItem = (DWORD)lpNMCustomDraw->nmcd.dwItemSpec;

					// Leave a pixel gap above and below the drawn rectangle
					if (IsAeroThemed())
						rcRect.InflateRect(0, -2);
					else
						rcRect.InflateRect(0, -1);

					if (IsMDIChildMaxed() && (0 == dwItem))
					// Draw over MDI Max button
					{
						HICON hIcon = (HICON)::SendMessage(GetActiveMDIChild(), WM_GETICON, ICON_SMALL, 0L);
						if (NULL == hIcon)
							hIcon = ::LoadIcon(NULL, IDI_APPLICATION);

						int cx = ::GetSystemMetrics (SM_CXSMICON);
						int cy = ::GetSystemMetrics (SM_CYSMICON);
						int y = 1 + (GetWindowRect().Height() - cy)/2;
						int x = (rcRect.Width() - cx)/2;
						pDrawDC->DrawIconEx(x, y, hIcon, cx, cy, 0, NULL, DI_NORMAL);

						pDrawDC->Detach();	// Optional, deletes GDI objects sooner
						return CDRF_SKIPDEFAULT;  // No further drawing
					}

					else if (nState & (CDIS_HOT | CDIS_SELECTED))
					{
						if ((nState & CDIS_SELECTED) || (GetButtonState(dwItem) & TBSTATE_PRESSED))
						{
							pDrawDC->GradientFill(m_ThemeMenu.clrPressed1, m_ThemeMenu.clrPressed2, rcRect, FALSE);
						}
						else if (nState & CDIS_HOT)
						{
							pDrawDC->GradientFill(m_ThemeMenu.clrHot1, m_ThemeMenu.clrHot2, rcRect, FALSE);
						}

						// Draw border
						pDrawDC->CreatePen(PS_SOLID, 1, m_ThemeMenu.clrOutline);
						pDrawDC->MoveTo(rcRect.left, rcRect.bottom);
						pDrawDC->LineTo(rcRect.left, rcRect.top);
						pDrawDC->LineTo(rcRect.right-1, rcRect.top);
						pDrawDC->LineTo(rcRect.right-1, rcRect.bottom);
						pDrawDC->MoveTo(rcRect.right-1, rcRect.bottom);
						pDrawDC->LineTo(rcRect.left, rcRect.bottom);

						TCHAR str[80] = _T("");
						int nLength = (int)SendMessage(TB_GETBUTTONTEXT, lpNMCustomDraw->nmcd.dwItemSpec, 0L);
						if ((nLength > 0) && (nLength < 80))
							SendMessage(TB_GETBUTTONTEXT, lpNMCustomDraw->nmcd.dwItemSpec, (LPARAM)str);

						// Draw highlight text
						pDrawDC->SelectObject(GetFont());
						rcRect.bottom += 1;
						int iMode = pDrawDC->SetBkMode(TRANSPARENT);
						pDrawDC->DrawText(str, lstrlen(str), rcRect, DT_VCENTER | DT_CENTER | DT_SINGLELINE);

						pDrawDC->SetBkMode(iMode);
						pDrawDC->Detach();	// Optional, deletes GDI objects sooner
						return CDRF_SKIPDEFAULT;  // No further drawing
					} 
				} 
				return CDRF_DODEFAULT ;   // Do default drawing

			// Painting cycle has completed
			case CDDS_POSTPAINT:
				// Draw MDI Minimise, Restore and Close buttons
				{
					CDC* pDrawDC = FromHandle(lpNMCustomDraw->nmcd.hdc);
					DrawAllMDIButtons(*pDrawDC);
					pDrawDC->Detach();	// Optional, deletes GDI objects sooner
				}
				break;
			}
		} 
		return 0L;
	}

	inline void CMenuBar::OnKeyDown(WPARAM wParam, LPARAM lParam)
	{
		UNREFERENCED_PARAMETER(lParam);

		switch (wParam)
		{
		case VK_ESCAPE:
			ExitMenu();
			break;

		case VK_SPACE:
			ExitMenu();
			// Bring up the system menu
			GetAncestor()->PostMessage(WM_SYSCOMMAND, SC_KEYMENU, VK_SPACE);
			break;

		// Handle VK_DOWN,VK_UP and VK_RETURN together
		case VK_DOWN:
		case VK_UP:
		case VK_RETURN:
			// Always use PostMessage for USER_POPUPMENU (not SendMessage)
			PostMessage(UWM_POPUPMENU, 0L, 0L);
			break;

		case VK_LEFT:
			// Move left to next topmenu item
			(m_nHotItem > 0)? SetHotItem(m_nHotItem -1) : SetHotItem(GetButtonCount()-1);
			break;

		case VK_RIGHT:
			// Move right to next topmenu item
			(m_nHotItem < GetButtonCount() -1)? SetHotItem(m_nHotItem +1) : SetHotItem(0);
			break;

		default:
			// Handle Accelerator keys with Alt toggled down
			if (m_bKeyMode)
			{
				UINT ID;
				if (SendMessage(TB_MAPACCELERATOR, wParam, (LPARAM) &ID))
				{
					m_nHotItem = ID;
					PostMessage(UWM_POPUPMENU, 0L, 0L);
				}
				else
					::MessageBeep(MB_OK);
			}
			break;
		} // switch (wParam)
	}

	inline void CMenuBar::OnLButtonDown(WPARAM wParam, LPARAM lParam)
	{
		UNREFERENCED_PARAMETER(wParam);

		GrabFocus();
		m_nMDIButton = 0;
		CPoint pt;

		pt.x = GET_X_LPARAM(lParam);
		pt.y = GET_Y_LPARAM(lParam);

		if (IsMDIFrame())
		{
			if (IsMDIChildMaxed())
			{
				CClientDC MenuBarDC(this);
				m_nMDIButton = -1;

				if (m_MDIRect[0].PtInRect(pt)) m_nMDIButton = 0;
				if (m_MDIRect[1].PtInRect(pt)) m_nMDIButton = 1;
				if (m_MDIRect[2].PtInRect(pt)) m_nMDIButton = 2;

				if (m_nMDIButton >= 0)
				{
					DrawMDIButton(MenuBarDC, MDI_MIN,     (0 == m_nMDIButton)? 2 : 0);
					DrawMDIButton(MenuBarDC, MDI_RESTORE, (1 == m_nMDIButton)? 2 : 0);
					DrawMDIButton(MenuBarDC, MDI_CLOSE,   (2 == m_nMDIButton)? 2 : 0);
				}

				// Bring up the MDI Child window's system menu when the icon is pressed
				if (0 == HitTest())
				{
					m_nHotItem = 0;
					PostMessage(UWM_POPUPMENU, 0L, 0L);
				}
			}
		}
	}

	inline void CMenuBar::OnLButtonUp(WPARAM wParam, LPARAM lParam)
	{
		UNREFERENCED_PARAMETER(wParam);
		CPoint pt;
		pt.x = GET_X_LPARAM(lParam);
		pt.y = GET_Y_LPARAM(lParam);

		if (IsMDIFrame())
		{
			HWND MDIClient = m_pFrame->GetView()->GetHwnd();
			HWND MDIChild = GetActiveMDIChild();

			if (IsMDIChildMaxed())
			{
				CPoint pt = GetCursorPos();
				ScreenToClient(pt);

				// Process the MDI button action when the left mouse button is up
				if (m_MDIRect[0].PtInRect(pt))
				{
					if (MDI_MIN == m_nMDIButton)
						::ShowWindow(MDIChild, SW_MINIMIZE);
				}

				if (m_MDIRect[1].PtInRect(pt))
				{
					if (MDI_RESTORE == m_nMDIButton)
					::PostMessage(MDIClient, WM_MDIRESTORE, (WPARAM)MDIChild, 0L);
				}

				if (m_MDIRect[2].PtInRect(pt))
				{
					if (MDI_CLOSE == m_nMDIButton)
						::PostMessage(MDIChild, WM_CLOSE, 0L, 0L);
				}
			}
		}
		m_nMDIButton = 0;
		ExitMenu();
	}

	inline BOOL CMenuBar::OnMenuInput(UINT uMsg, WPARAM wParam, LPARAM lParam)
	// When a popup menu is active, StaticMsgHook directs all menu messages here
	{
		switch(uMsg)
		{
		case WM_KEYDOWN:
			m_bExitAfter = FALSE;
			{
				switch (wParam)
				{
				case VK_ESCAPE:
					// Use default processing if inside a Sub Menu
					if ((m_hSelMenu) &&(m_hSelMenu != m_hPopupMenu))
						return FALSE;

					m_bMenuActive = FALSE;
					m_bKeyMode = TRUE;
					SendMessage(WM_CANCELMODE, 0L, 0L);
					SendMessage(TB_PRESSBUTTON, m_nHotItem, MAKELONG(FALSE, 0));
					SendMessage(TB_SETHOTITEM, m_nHotItem, 0L);
					break;

				case VK_LEFT:
					// Use default processing if inside a Sub Menu
				    if ((m_hSelMenu) &&(m_hSelMenu != m_hPopupMenu))
						return FALSE;

					SendMessage(TB_PRESSBUTTON, m_nHotItem, MAKELONG(FALSE, 0));

					// Move left to next topmenu item
					(m_nHotItem > 0)? --m_nHotItem : m_nHotItem = GetButtonCount()-1;
					SendMessage(WM_CANCELMODE, 0L, 0L);

					// Always use PostMessage for USER_POPUPMENU (not SendMessage)
					PostMessage(UWM_POPUPMENU, 0L, 0L);
					PostMessage(WM_KEYDOWN, VK_DOWN, 0L);
					break;

				case VK_RIGHT:
					// Use default processing to open Sub Menu
					if (m_bSelPopup)
						return FALSE;

					SendMessage(TB_PRESSBUTTON, m_nHotItem, MAKELONG(FALSE, 0));

					// Move right to next topmenu item
					(m_nHotItem < GetButtonCount()-1)? ++m_nHotItem : m_nHotItem = 0;
					SendMessage(WM_CANCELMODE, 0L, 0L);

					// Always use PostMessage for USER_POPUPMENU (not SendMessage)
					PostMessage(UWM_POPUPMENU, 0L, 0L);
					PostMessage(WM_KEYDOWN, VK_DOWN, 0L);
					break;

				case VK_RETURN:
					m_bExitAfter = TRUE;
					break;

				} // switch (wParam)

			} // case WM_KEYDOWN

			return FALSE;

		case WM_CHAR:
			m_bExitAfter = TRUE;
			return FALSE;

		case WM_LBUTTONDOWN:
			{
				m_bExitAfter = TRUE;
				if (HitTest() >= 0)
				{
					// Cancel popup when we hit a button a second time
					SendMessage(WM_CANCELMODE, 0L, 0L);
					return TRUE;
				}
			}
			return FALSE;

		case WM_LBUTTONDBLCLK:
			// Perform default action for DblClick on MDI Maxed icon
			if (IsMDIChildMaxed() && (0 == HitTest()))
			{
				CWnd* pMDIChild = FromHandle(GetActiveMDIChild());
				CMenu* pChildMenu = pMDIChild->GetSystemMenu(FALSE);

				UINT nID = pChildMenu->GetDefaultItem(FALSE, 0);
				if (nID)
					pMDIChild->PostMessage(WM_SYSCOMMAND, nID, 0L);
			}

			m_bExitAfter = TRUE;
			return FALSE;

		case WM_MENUSELECT:
			{
				// store info about selected item
				m_hSelMenu = (HMENU)lParam;
				m_bSelPopup = ((HIWORD(wParam) & MF_POPUP) != 0);

				// Reflect message back to the frame window
				GetAncestor()->SendMessage(WM_MENUSELECT, wParam, lParam);
			}
			return TRUE;

		case WM_MOUSEMOVE:
			{
				CPoint pt;
				pt.x = GET_X_LPARAM(lParam);
				pt.y = GET_Y_LPARAM(lParam);

				// Skip if mouse hasn't moved
				if ((pt.x == m_OldMousePos.x) && (pt.y == m_OldMousePos.y))
					return FALSE;

				m_OldMousePos.x = pt.x;
				m_OldMousePos.y = pt.y;
				ScreenToClient(pt);

				// Reflect messages back to the MenuBar for hot tracking
				SendMessage(WM_MOUSEMOVE, 0L, MAKELPARAM(pt.x, pt.y));
			}
			break;

		}
		return FALSE;
	}

	inline void CMenuBar::OnMouseLeave()
	{
		if (IsMDIFrame())
		{
			if (IsMDIChildMaxed())
			{
				CClientDC MenuBarDC(this);

				DrawMDIButton(MenuBarDC, MDI_MIN,     0);
				DrawMDIButton(MenuBarDC, MDI_RESTORE, 0);
				DrawMDIButton(MenuBarDC, MDI_CLOSE,   0);
			}
		}
	}

	inline void CMenuBar::OnMouseMove(WPARAM wParam, LPARAM lParam)
	{
		CPoint pt;
		pt.x = GET_X_LPARAM(lParam);
		pt.y = GET_Y_LPARAM(lParam);

		if (IsMDIFrame())
		{
			if (IsMDIChildMaxed())
			{
				CClientDC MenuBarDC(this);
				int MDIButton = -1;
				if (m_MDIRect[0].PtInRect(pt)) MDIButton = 0;
				if (m_MDIRect[1].PtInRect(pt)) MDIButton = 1;
				if (m_MDIRect[2].PtInRect(pt)) MDIButton = 2;

				if (MK_LBUTTON == wParam)  // mouse moved with left mouse button is held down
				{
					// toggle the MDI button image pressed/unpressed as required
					if (MDIButton >= 0)
					{
						DrawMDIButton(MenuBarDC, MDI_MIN,     ((0 == MDIButton) && (0 == m_nMDIButton))? 2 : 0);
						DrawMDIButton(MenuBarDC, MDI_RESTORE, ((1 == MDIButton) && (1 == m_nMDIButton))? 2 : 0);
						DrawMDIButton(MenuBarDC, MDI_CLOSE,   ((2 == MDIButton) && (2 == m_nMDIButton))? 2 : 0);
					}
					else
					{
						DrawMDIButton(MenuBarDC, MDI_MIN,     0);
						DrawMDIButton(MenuBarDC, MDI_RESTORE, 0);
						DrawMDIButton(MenuBarDC, MDI_CLOSE,   0);
					}
				}
				else	// mouse moved without left mouse button held down
				{
					if (MDIButton >= 0)
					{
						DrawMDIButton(MenuBarDC, MDI_MIN,     (0 == MDIButton)? 1 : 0);
						DrawMDIButton(MenuBarDC, MDI_RESTORE, (1 == MDIButton)? 1 : 0);
						DrawMDIButton(MenuBarDC, MDI_CLOSE,   (2 == MDIButton)? 1 : 0);
					}
					else
					{
						DrawMDIButton(MenuBarDC, MDI_MIN,     0);
						DrawMDIButton(MenuBarDC, MDI_RESTORE, 0);
						DrawMDIButton(MenuBarDC, MDI_CLOSE,   0);
					}
				}
			}
		}
	}

	inline LRESULT CMenuBar::OnNotifyReflect(WPARAM wParam, LPARAM lParam)
	{
		UNREFERENCED_PARAMETER(wParam);

		switch (((LPNMHDR)lParam)->code)
		{
		case NM_CUSTOMDRAW:
			{
				return OnCustomDraw((LPNMHDR) lParam);
			}

		case TBN_DROPDOWN:
			// Always use PostMessage for USER_POPUPMENU (not SendMessage)
			PostMessage(UWM_POPUPMENU, 0L, 0L);
			break;

		case TBN_HOTITEMCHANGE:
			// This is the notification that a hot item change is about to occur
			// This is used to bring up a new popup menu when required
			{
				CPoint pt = GetCursorPos();
				if (this == WindowFromPoint(pt))	// MenuBar window must be on top
				{
					DWORD flag = ((LPNMTBHOTITEM)lParam)->dwFlags;
					if ((flag & HICF_MOUSE) && !(flag & HICF_LEAVING))
					{
						int nButton = HitTest();
						if ((m_bMenuActive) && (nButton != m_nHotItem))
						{
							SendMessage(TB_PRESSBUTTON, m_nHotItem, MAKELONG(FALSE, 0));
							m_nHotItem = nButton;
							SendMessage(WM_CANCELMODE, 0L, 0L);

							//Always use PostMessage for USER_POPUPMENU (not SendMessage)
							PostMessage(UWM_POPUPMENU, 0L, 0L);
						}
						m_nHotItem = nButton;
					}

					// Handle escape from popup menu
					if ((flag & HICF_LEAVING) && m_bKeyMode)
					{
						m_nHotItem = ((LPNMTBHOTITEM)lParam)->idOld;
						PostMessage(TB_SETHOTITEM, m_nHotItem, 0L);
					}

				}
				break;
			} //case TBN_HOTITEMCHANGE:

		} // switch(((LPNMHDR)lParam)->code)
		return 0L;
	} // CMenuBar::OnNotify(...)

	inline void CMenuBar::OnWindowPosChanged()
	{
		InvalidateRect(&m_MDIRect[0], TRUE);
		InvalidateRect(&m_MDIRect[1], TRUE);
		InvalidateRect(&m_MDIRect[2], TRUE);
		{
			CClientDC MenuBarDC(this);
			DrawAllMDIButtons(MenuBarDC);
		}
	}

	inline void CMenuBar::PreCreate(CREATESTRUCT &cs)
	{
		cs.style = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | TBSTYLE_LIST | TBSTYLE_FLAT | CCS_NODIVIDER | CCS_NORESIZE;
	}

	inline void CMenuBar::PreRegisterClass(WNDCLASS &wc)
	{
		// Set the Window Class
		wc.lpszClassName =  TOOLBARCLASSNAME;
	}

	inline void CMenuBar::ReleaseFocus()
	{
		if (m_hPrevFocus)
			::SetFocus(m_hPrevFocus);

		m_hPrevFocus = NULL;
		::ReleaseCapture();
	}

	inline void CMenuBar::SetHotItem(int nHot)
	{
		m_nHotItem = nHot;
		SendMessage(TB_SETHOTITEM, m_nHotItem, 0L);
	}

	inline void CMenuBar::SetMenu(HMENU hMenu)
	{
		assert(::IsWindow(m_hWnd));

		m_hTopMenu = hMenu;
		int nMaxedOffset = (IsMDIChildMaxed()? 1:0);

		// Remove any existing buttons
		while (SendMessage(TB_BUTTONCOUNT,  0L, 0L) > 0)
		{
			if(!SendMessage(TB_DELETEBUTTON, 0L, 0L))
				break;
		}

		// Set the Bitmap size to zero
		SendMessage(TB_SETBITMAPSIZE, 0L, MAKELPARAM(0, 0));

		if (IsMDIChildMaxed())
		{
			// Create an extra button for the MDI child system menu
			// Later we will custom draw the window icon over this button
			TBBUTTON tbb = {0};
			tbb.fsState = TBSTATE_ENABLED;
			tbb.fsStyle = TBSTYLE_BUTTON | TBSTYLE_AUTOSIZE ;
			tbb.iString = (INT_PTR)_T(" ");
			SendMessage(TB_ADDBUTTONS, 1, (WPARAM)&tbb);
			SetButtonText(0, _T("    "));
		}

		for (int i = 0 ; i < ::GetMenuItemCount(hMenu); ++i)
		{
			// Assign the ToolBar Button struct
			TBBUTTON tbb = {0};
			tbb.idCommand = i  + nMaxedOffset;	// Each button needs a unique ID
			tbb.fsState = TBSTATE_ENABLED;
			tbb.fsStyle = TBSTYLE_BUTTON | TBSTYLE_AUTOSIZE | TBSTYLE_DROPDOWN;
			tbb.iString = (INT_PTR)_T(" ");
			SendMessage(TB_ADDBUTTONS, 1, (WPARAM)&tbb);

			// Add the menu title to the string table
			std::vector<TCHAR> vMenuName( MAX_MENU_STRING+1, _T('\0') );
			TCHAR* szMenuName = &vMenuName[0];
			GetMenuString(hMenu, i, szMenuName, MAX_MENU_STRING, MF_BYPOSITION);
			SetButtonText(i  + nMaxedOffset, szMenuName);
		}
	}

	inline void CMenuBar::SetMenuBarTheme(MenuTheme& Theme)
	{
		m_ThemeMenu.UseThemes   = Theme.UseThemes;
		m_ThemeMenu.clrHot1     = Theme.clrHot1;
		m_ThemeMenu.clrHot2     = Theme.clrHot2;
		m_ThemeMenu.clrPressed1 = Theme.clrPressed1;
		m_ThemeMenu.clrPressed2 = Theme.clrPressed2;
		m_ThemeMenu.clrOutline  = Theme.clrOutline;

		if (IsWindow())
			Invalidate();
	}

	inline LRESULT CALLBACK CMenuBar::StaticMsgHook(int nCode, WPARAM wParam, LPARAM lParam)
	{
		assert(GetApp());
		MSG* pMsg = (MSG*)lParam;
		TLSData* pTLSData = (TLSData*)TlsGetValue(GetApp()->GetTlsIndex());
		assert(pTLSData);
		CMenuBar* pMenuBar = (CMenuBar*)pTLSData->pMenuBar;

		if (pMenuBar && (MSGF_MENU == nCode))
		{
			// process menu message
			if (pMenuBar->OnMenuInput(pMsg->message, pMsg->wParam, pMsg->lParam))
			{
				return TRUE;
			}
		}

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

	inline void CMenuBar::OnSysCommand(WPARAM wParam, LPARAM lParam)
	{
		if (SC_KEYMENU == wParam)
		{
			if (0 == lParam)
			{
				// Alt/F10 key toggled
				GrabFocus();
				m_bKeyMode = TRUE;
				int nMaxedOffset = (IsMDIChildMaxed()? 1:0);
				SetHotItem(nMaxedOffset);
			}
			else
				// Handle key pressed with Alt held down
				DoAltKey((WORD)lParam);
		}
	}

	inline LRESULT CMenuBar::WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam)
	{
		switch (uMsg)
		{
		case WM_CHAR:
			return 0L;  // Discard these messages
		case WM_DRAWITEM:
			m_pFrame->OnDrawItem(wParam, lParam);
			return TRUE; // handled
		case WM_EXITMENULOOP:
			if (m_bExitAfter)
				ExitMenu();
			m_pFrame->OnExitMenuLoop();
			break;
		case WM_INITMENUPOPUP:
			m_pFrame->OnInitMenuPopup(wParam, lParam);
			break;
		case WM_KEYDOWN:
			OnKeyDown(wParam, lParam);
			return 0L;	// Discard these messages
		case WM_KILLFOCUS:
			ExitMenu();
			return 0L;
		case WM_LBUTTONDOWN:
			// Do default processing first
			CallWindowProc(GetPrevWindowProc(), uMsg, wParam, lParam);

			OnLButtonDown(wParam, lParam);
			return 0L;
		case WM_LBUTTONUP:
			OnLButtonUp(wParam, lParam);
			break;
		case WM_MEASUREITEM:
			m_pFrame->OnMeasureItem(wParam, lParam);
			return TRUE; // handled
		case WM_MOUSELEAVE:
			OnMouseLeave();
			break;
		case WM_MOUSEMOVE:
			OnMouseMove(wParam, lParam);
			break;
		case UWM_POPUPMENU:
			DoPopupMenu();
			return 0L;
		case WM_SYSKEYDOWN:
			if ((VK_MENU == wParam) || (VK_F10 == wParam))
				return 0L;
			break;
		case WM_SYSKEYUP:
			if ((VK_MENU == wParam) || (VK_F10 == wParam))
			{
				ExitMenu();
				return 0L;
			}
			break;
		case UWM_GETMENUTHEME:
			{
				MenuTheme& tm = GetMenuBarTheme();
				return (LRESULT)&tm;
			}
		case WM_WINDOWPOSCHANGED:
			OnWindowPosChanged();
			break;
		case WM_WINDOWPOSCHANGING:
			// Bypass CToolBar::WndProcDefault for this message
			return CWnd::WndProcDefault(uMsg, wParam, lParam);

		} // switch (uMsg)

		return CToolBar::WndProcDefault(uMsg, wParam, lParam);
	} // LRESULT CMenuBar::WndProcDefault(...)



	///////////////////////////////////
	// Definitions for the CFrame class
	//
	inline CFrame::CFrame() : m_tsStatusText(_T("Ready")), m_bShowIndicatorStatus(TRUE), m_bShowMenuStatus(TRUE),
		                m_bUseReBar(FALSE), m_bUseThemes(TRUE), m_bUpdateTheme(FALSE), m_bUseToolBar(TRUE), m_bUseCustomDraw(TRUE),
						m_bShowStatusBar(TRUE), m_bShowToolBar(TRUE), m_himlMenu(NULL), m_himlMenuDis(NULL),
						m_AboutDialog(IDW_ABOUT), m_pView(NULL), m_nMaxMRU(0), m_hOldFocus(0), m_nOldID(-1)
	{
		ZeroMemory(&m_ThemeMenu, sizeof(m_ThemeMenu));

		// Do either InitCommonControls or InitCommonControlsEx
		LoadCommonControls();

		// By default, we use the rebar if we can
		if (GetComCtlVersion() >= 470)
			m_bUseReBar = TRUE;

		for (int i = 0 ; i < 3 ; ++i)
			m_OldStatus[i] = _T('\0');
	}

	inline CFrame::~CFrame()
	{
		if (m_himlMenu) ImageList_Destroy(m_himlMenu);
		if (m_himlMenuDis) ImageList_Destroy(m_himlMenuDis);
	}

	inline BOOL CFrame::AddMenuIcon(int nID_MenuItem, HICON hIcon, int cx /*= 16*/, int cy /*= 16*/)
	{
		// Get ImageList image size
		int cxOld = 0;
		int cyOld = 0;
		ImageList_GetIconSize(m_himlMenu, &cxOld, &cyOld );

		// Create a new ImageList if required
		if ((cx != cxOld) || (cy != cyOld) || (NULL == m_himlMenu))
		{
			if (m_himlMenu) ImageList_Destroy(m_himlMenu);
			m_himlMenu = ImageList_Create(cx, cy, ILC_COLOR32 | ILC_MASK, 1, 0);
			m_vMenuIcons.clear();
		}

        if (ImageList_AddIcon(m_himlMenu, hIcon) != -1)
		{
			m_vMenuIcons.push_back(nID_MenuItem);

			// Recreate the Disabled imagelist
			if (m_himlMenuDis) ImageList_Destroy(m_himlMenuDis);
			m_himlMenuDis = NULL;
			m_himlMenuDis = CreateDisabledImageList(m_himlMenu);

			return TRUE;
		}

		return FALSE;
	}

	inline UINT CFrame::AddMenuIcons(const std::vector<UINT>& MenuData, COLORREF crMask, UINT ToolBarID, UINT ToolBarDisabledID)
	// Adds the icons from a bitmap resouce to an internal ImageList for use with popup menu items.
	// Note:  If existing are a different size to the new ones, the old ones will be removed!
	//        The ToolBarDisabledID is ignored unless ToolBarID and ToolBarDisabledID bitmaps are the same size.
	{
		// Count the MenuData entries excluding seperators
		int iImages = 0;
		for (UINT i = 0 ; i < MenuData.size(); ++i)
		{
			if (MenuData[i] != 0)	// Don't count seperators
			{
				++iImages;
			}
		}

		// Load the button images from Resouce ID
		CBitmap Bitmap(ToolBarID);

		if ((0 == iImages) || (!Bitmap))
			return (UINT)m_vMenuIcons.size();	// No valid images, so nothing to do!

		BITMAP bm = Bitmap.GetBitmapData();
		int iImageWidth  = bm.bmWidth / iImages;
		int iImageHeight = bm.bmHeight;

		// Create the ImageList if required
		if (NULL == m_himlMenu)
		{
			m_himlMenu = ImageList_Create(iImageWidth, iImageHeight, ILC_COLOR32 | ILC_MASK, iImages, 0);
			m_vMenuIcons.clear();
		}
		else
		{
			int Oldcx;
			int Oldcy;

			ImageList_GetIconSize(m_himlMenu, &Oldcx, &Oldcy);
			if (iImageHeight != Oldcy)
			{
				TRACE(_T("Unable to add icons. The new icons are a different size to the old ones\n"));
				return (UINT)m_vMenuIcons.size();
			}
		}

		// Add the resource IDs to the m_vMenuIcons vector
		for (UINT j = 0 ; j < MenuData.size(); ++j)
		{
			if (MenuData[j] != 0)
			{
				m_vMenuIcons.push_back(MenuData[j]);
			}
		}

		// Add the images to the ImageList
		ImageList_AddMasked(m_himlMenu, Bitmap, crMask);

		// Create the Disabled imagelist
		if (ToolBarDisabledID)
		{
			if (0 != m_himlMenuDis)
				m_himlMenuDis = ImageList_Create(iImageWidth, iImageHeight, ILC_COLOR32 | ILC_MASK, iImages, 0);

			CBitmap BitmapDisabled(ToolBarDisabledID);
			BITMAP bmDis = BitmapDisabled.GetBitmapData();

			int iImageWidthDis  = bmDis.bmWidth / iImages;
			int iImageHeightDis = bmDis.bmHeight;

			// Normal and Disabled icons must be the same size
			if ((iImageWidthDis == iImageWidth) && (iImageHeightDis == iImageHeight))
			{
				ImageList_AddMasked(m_himlMenu, BitmapDisabled, crMask);
			}
			else
			{
				ImageList_Destroy(m_himlMenuDis);
				m_himlMenuDis = CreateDisabledImageList(m_himlMenu);
			}
		}
		else
		{
			if (m_himlMenuDis) ImageList_Destroy(m_himlMenuDis);
			m_himlMenuDis = CreateDisabledImageList(m_himlMenu);
		}

		// return the number of menu icons
		return (UINT)m_vMenuIcons.size();
	}

	inline void CFrame::AddMenuBarBand()
	{
		// Adds a MenuBar to the rebar control
		REBARBANDINFO rbbi = {0};
		CSize sz = GetMenuBar().GetMaxSize();

		// Calculate the MenuBar height from the menu font
		CSize csMenuBar;
		CClientDC dcMenuBar(&GetMenuBar());
		dcMenuBar.SelectObject(GetMenuBar().GetFont());
		csMenuBar = dcMenuBar.GetTextExtentPoint32(_T("\tSomeText"), lstrlen(_T("\tSomeText")));
		int MenuBar_Height = csMenuBar.cy + 6;

		rbbi.fMask      = RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_CHILD | RBBIM_SIZE | RBBIM_ID;
		rbbi.cxMinChild = sz.cx;
		rbbi.cx         = sz.cx;
		rbbi.cyMinChild = MenuBar_Height;
		rbbi.cyMaxChild = MenuBar_Height;
		rbbi.fStyle     = RBBS_BREAK | RBBS_VARIABLEHEIGHT | RBBS_GRIPPERALWAYS ;
		rbbi.hwndChild  = GetMenuBar();
		rbbi.wID        = IDW_MENUBAR;

		// Note: rbbi.cbSize is set inside the InsertBand function
		GetReBar().InsertBand(-1, rbbi);
		SetMenuBarBandSize();
		GetReBar().SetMenuBar(GetMenuBar());

		if (GetReBar().GetReBarTheme().LockMenuBand)
			GetReBar().ShowGripper(GetReBar().GetBand(GetMenuBar()), FALSE);
	}

	inline void CFrame::AddMRUEntry(LPCTSTR szMRUEntry)
	{
		// Erase possible duplicate entries from vector
		RemoveMRUEntry(szMRUEntry);

		// Insert the entry at the beginning of the vector
		m_vMRUEntries.insert(m_vMRUEntries.begin(), szMRUEntry);

		// Delete excessive MRU entries
		if (m_vMRUEntries.size() > m_nMaxMRU)
			m_vMRUEntries.erase(m_vMRUEntries.begin() + m_nMaxMRU, m_vMRUEntries.end());

		UpdateMRUMenu();
	}

	inline void CFrame::AddToolBarBand(CToolBar& TB, DWORD dwStyle, UINT nID)
	{
		// Adds a ToolBar to the rebar control

		// Create the ToolBar Window
		TB.Create(&GetReBar());

		// Fill the REBARBAND structure
		REBARBANDINFO rbbi = {0};
		CSize sz = TB.GetMaxSize();

		rbbi.fMask      = RBBIM_CHILDSIZE | RBBIM_STYLE |  RBBIM_CHILD | RBBIM_SIZE | RBBIM_ID;
		rbbi.cyMinChild = sz.cy;
		rbbi.cyMaxChild = sz.cy;
		rbbi.cx         = sz.cx +2;
		rbbi.cxMinChild = sz.cx +2;

		rbbi.fStyle     = dwStyle;
		rbbi.hwndChild  = TB;
		rbbi.wID        = nID;

		// Note: rbbi.cbSize is set inside the InsertBand function
		GetReBar().InsertBand(-1, rbbi);
	}

	inline void CFrame::AddToolBarButton(UINT nID, BOOL bEnabled /* = TRUE*/, LPCTSTR szText)
	// Adds Resource IDs to toolbar buttons.
	// A resource ID of 0 is a separator
	{
		GetToolBar().AddButton(nID, bEnabled);

		if(0 != szText)
			GetToolBar().SetButtonText(nID, szText);

		if (!IsWindow()) TRACE(_T("Warning ... Resource IDs for toolbars should be added in SetupToolBar\n"));
	}

	inline void CFrame::AdjustFrameRect(RECT rcView) const
	// Adjust the size of the frame to accommodate the View window's dimensions
	{
		// Adjust for the view styles
		CRect rc = rcView;
		DWORD dwStyle = (DWORD)GetView()->GetWindowLongPtr(GWL_STYLE);
		DWORD dwExStyle = (DWORD)GetView()->GetWindowLongPtr(GWL_EXSTYLE);
		AdjustWindowRectEx(&rc, dwStyle, FALSE, dwExStyle);

		// Calculate the new frame height
		CRect rcFrameBefore = GetWindowRect();
		CRect rcViewBefore = GetViewRect();
		int Height = rc.Height() + rcFrameBefore.Height() - rcViewBefore.Height();

		// Adjust for the frame styles
		dwStyle = (DWORD)GetWindowLongPtr(GWL_STYLE);
		dwExStyle = (DWORD)GetWindowLongPtr(GWL_EXSTYLE);
		AdjustWindowRectEx(&rc, dwStyle, FALSE, dwExStyle);

		// Calculate final rect size, and reposition frame
		SetWindowPos(NULL, 0, 0, rc.Width(), Height, SWP_NOMOVE);
	}

	inline void CFrame::CreateToolBar()
	{
		if (IsReBarSupported() && m_bUseReBar)
			AddToolBarBand(GetToolBar(), RBBS_BREAK, IDW_TOOLBAR);	// Create the toolbar inside rebar
		else
			GetToolBar().Create(this);	// Create the toolbar without a rebar

		SetupToolBar();

		if (IsReBarSupported() && m_bUseReBar)
		{
			if (GetReBar().GetReBarTheme().UseThemes && GetReBar().GetReBarTheme().LockMenuBand)
			{
				// Hide gripper for single toolbar
				if (GetReBar().GetBandCount() <= 2)
					GetReBar().ShowGripper(GetReBar().GetBand(GetToolBar()), FALSE);
			}
		}

		if (GetToolBar().GetToolBarData().size() > 0)
		{
			// Set the toolbar images (if not already set in SetupToolBar)
			// A mask of 192,192,192 is compatible with AddBitmap (for Win95)
			if (!GetToolBar().SendMessage(TB_GETIMAGELIST,  0L, 0L))
				SetToolBarImages(RGB(192,192,192), IDW_MAIN, 0, 0);

			// Add the icons for popup menu
			AddMenuIcons(GetToolBar().GetToolBarData(), RGB(192, 192, 192), IDW_MAIN, 0);
		}
		else
		{
			TRACE(_T("Warning ... No resource IDs assigned to the toolbar\n"));
		}
	}

	inline void CFrame::DrawCheckmark(LPDRAWITEMSTRUCT pdis, CDC& DrawDC)
	// Draws the checkmark or radiocheck transparently
	{
		CRect rc = pdis->rcItem;
		UINT fType = ((ItemData*)pdis->itemData)->fType;
		MenuTheme tm = GetMenuTheme();
		CRect rcBk;

		// Draw the checkmark's background rectangle first
		int Iconx = 16, Icony = 16;
		if (m_himlMenu) ImageList_GetIconSize(m_himlMenu, &Iconx, &Icony);
		int BarWidth = Iconx + 8;
		int left = (BarWidth - Iconx)/2;
		int top = rc.top + (rc.Height() - Icony)/2;
		rcBk.SetRect(left, top, left + Iconx, top + Icony);

		if (tm.UseThemes)
		{
			DrawDC.CreateSolidBrush(tm.clrHot2);
			DrawDC.CreatePen(PS_SOLID, 1, tm.clrOutline);

			// Draw the checkmark's background rectangle
			DrawDC.Rectangle(rcBk.left, rcBk.top, rcBk.right, rcBk.bottom);
		}

		CMemDC MemDC(FromHandle(pdis->hDC));
		int cxCheck = ::GetSystemMetrics(SM_CXMENUCHECK);
		int cyCheck = ::GetSystemMetrics(SM_CYMENUCHECK);
		MemDC.CreateBitmap(cxCheck, cyCheck, 1, 1, NULL);
		CRect rcCheck( 0, 0, cxCheck, cyCheck);

		// Copy the check mark bitmap to hdcMem
		if (MFT_RADIOCHECK == fType)
			MemDC.DrawFrameControl(rcCheck, DFC_MENU, DFCS_MENUBULLET);
		else
			MemDC.DrawFrameControl(rcCheck, DFC_MENU, DFCS_MENUCHECK);

		int xoffset = (rcBk.Width() - rcCheck.Width()-1)/2;
		int yoffset = (rcBk.Height() - rcCheck.Height()-1)/2;

		if (tm.UseThemes)
			xoffset += 2;

		// Draw a white or black check mark as required
		// Unfortunately MaskBlt isn't supported on Win95, 98 or ME, so we do it the hard way
		CMemDC MaskDC(FromHandle(pdis->hDC));
		MaskDC.CreateCompatibleBitmap(FromHandle(pdis->hDC), cxCheck, cyCheck);
		MaskDC.BitBlt(0, 0, cxCheck, cyCheck, &MaskDC, 0, 0, WHITENESS);
		
		if ((pdis->itemState & ODS_SELECTED) && (!tm.UseThemes))
		{
			// Draw a white checkmark
			MemDC.BitBlt(0, 0, cxCheck, cyCheck, &MemDC, 0, 0, DSTINVERT);
			MaskDC.BitBlt(0, 0, cxCheck, cyCheck, &MemDC, 0, 0, SRCAND);
			DrawDC.BitBlt(rcBk.left + xoffset, rcBk.top + yoffset, cxCheck, cyCheck, &MaskDC, 0, 0, SRCPAINT);
		}
		else
		{
			// Draw a black checkmark
			int BullitOffset = ((MFT_RADIOCHECK == fType) && tm.UseThemes)? 1 : 0;
			MaskDC.BitBlt( -BullitOffset, BullitOffset, cxCheck, cyCheck, &MemDC, 0, 0, SRCAND);
			DrawDC.BitBlt(rcBk.left + xoffset, rcBk.top + yoffset, cxCheck, cyCheck, &MaskDC, 0, 0, SRCAND);
		}
	}

	inline void CFrame::DrawMenuIcon(LPDRAWITEMSTRUCT pdis, CDC& DrawDC, BOOL bDisabled)
	{
		if (!m_himlMenu)
			return;
		// Get icon size
		int Iconx;
		int Icony;
		ImageList_GetIconSize(m_himlMenu, &Iconx, &Icony);
		int BarWidth = Iconx + 8;

		// get the drawing rectangle
		CRect rc = pdis->rcItem;
		int left = (BarWidth - Iconx)/2;
		int top = rc.top + (rc.Height() - Icony)/2;
		rc.SetRect(left, top, left + Iconx, top + Icony);

		// get the icon's location in the imagelist
		int iImage = -1;
		for (int i = 0 ; i < (int)m_vMenuIcons.size(); ++i)
		{
			if (pdis->itemID == m_vMenuIcons[i])
				iImage = i;
		}

		// draw the image
		if (iImage >= 0 )
		{
			if ((bDisabled) && (m_himlMenuDis))
				ImageList_Draw(m_himlMenuDis, iImage, DrawDC, rc.left, rc.top, ILD_TRANSPARENT);
			else
				ImageList_Draw(m_himlMenu, iImage, DrawDC, rc.left, rc.top, ILD_TRANSPARENT);
		}
	}

	inline void CFrame::DrawMenuText(CDC& DrawDC, LPCTSTR ItemText, CRect& rc, COLORREF colorText)
	{
		// find the position of tab character
		int nTab = -1;
		for(int i = 0; i < lstrlen(ItemText); ++i)
		{
			if(_T('\t') == ItemText[i])
			{
				nTab = i;
				break;
			}
		}

		// Draw the item text
		DrawDC.SetTextColor(colorText);
		DrawDC.DrawText(ItemText, nTab, rc, DT_SINGLELINE | DT_LEFT | DT_VCENTER);

		// Draw text after tab, right aligned
		if(nTab != -1)
			DrawDC.DrawText( &ItemText[nTab + 1], -1, rc, DT_SINGLELINE | DT_RIGHT | DT_VCENTER);
	}

	inline int CFrame::GetMenuItemPos(HMENU hMenu, LPCTSTR szItem)
	// Returns the position of the menu item, given it's name
	{
		int nMenuItemCount = GetMenuItemCount(hMenu);
		MENUITEMINFO mii = {0};
		mii.cbSize = GetSizeofMenuItemInfo();

		for (int nItem = 0 ; nItem < nMenuItemCount; ++nItem)
		{
			std::vector<TCHAR> vTChar( MAX_MENU_STRING+1, _T('\0') );
			TCHAR* szStr = &vTChar[0];

			std::vector<TCHAR> vStripped( MAX_MENU_STRING+1, _T('\0') );
			TCHAR* szStripped = &vStripped[0];

			mii.fMask      = MIIM_TYPE;
			mii.fType      = MFT_STRING;
			mii.dwTypeData = szStr;
			mii.cch        = MAX_MENU_STRING;

			// Fill the contents of szStr from the menu item
			if (::GetMenuItemInfo(hMenu, nItem, TRUE, &mii) && (lstrlen(szStr) <= MAX_MENU_STRING))
			{
				// Strip out any & characters
				int j = 0;
				for (int i = 0; i < lstrlen(szStr); ++i)
				{
					if (szStr[i] != _T('&'))
						szStripped[j++] = szStr[i];
				}
				szStripped[j] = _T('\0');	// Append null tchar

				// Compare the strings
				if (0 == lstrcmp(szStripped, szItem))
					return nItem;
			}
		}

		return -1;
	}

	inline tString CFrame::GetMRUEntry(UINT nIndex)
	{
		tString tsPathName;
		if (nIndex < m_vMRUEntries.size())
		{
			tsPathName = m_vMRUEntries[nIndex];

			// Now put the selected entry at Index 0
			AddMRUEntry(tsPathName.c_str());
		}
		return tsPathName;
	}

	inline CRect CFrame::GetViewRect() const
	{
		// Get the frame's client area
		CRect rcFrame = GetClientRect();

		// Get the statusbar's window area
		CRect rcStatus;
		if (GetStatusBar().IsWindowVisible() || !IsWindowVisible())
			rcStatus = GetStatusBar().GetWindowRect();

		// Get the top rebar or toolbar's window area
		CRect rcTop;
		if (IsReBarSupported() && m_bUseReBar)
			rcTop = GetReBar().GetWindowRect();
		else
			if (GetToolBar().IsWindow() && GetToolBar().IsWindowVisible())
				rcTop = GetToolBar().GetWindowRect();

		// Return client size less the rebar and status windows
		int top = rcFrame.top + rcTop.Height();
		int left = rcFrame.left;
		int right = rcFrame.right;
		int bottom = rcFrame.Height() - (rcStatus.Height());
		if ((bottom <= top) ||( right <= left))
			top = left = right = bottom = 0;

		CRect rcView(left, top, right, bottom);
		return rcView;
	}

	inline void CFrame::LoadCommonControls()
	{
		HMODULE hComCtl;

		try
		{
			// Load the Common Controls DLL
			hComCtl = ::LoadLibrary(_T("COMCTL32.DLL"));
			if (!hComCtl)
				throw CWinException(_T("Failed to load COMCTL32.DLL"));

			if (GetComCtlVersion() > 470)
			{
				// Declare a pointer to the InItCommonControlsEx function
				typedef BOOL WINAPI INIT_EX(INITCOMMONCONTROLSEX*);
				INIT_EX* pfnInit = (INIT_EX*)::GetProcAddress(hComCtl, "InitCommonControlsEx");

				// Load the full set of common controls
				INITCOMMONCONTROLSEX InitStruct = {0};
				InitStruct.dwSize = sizeof(INITCOMMONCONTROLSEX);
				InitStruct.dwICC = ICC_COOL_CLASSES|ICC_DATE_CLASSES|ICC_INTERNET_CLASSES|ICC_NATIVEFNTCTL_CLASS|
							ICC_PAGESCROLLER_CLASS|ICC_USEREX_CLASSES|ICC_WIN95_CLASSES;

				// Call InitCommonControlsEx
				if(!((*pfnInit)(&InitStruct)))
					throw CWinException(_T("InitCommonControlsEx failed"));
			}
			else
			{
				::InitCommonControls();
			}

			::FreeLibrary(hComCtl);
		}

		catch (const CWinException &e)
		{
			e.what();
			if (hComCtl)
				::FreeLibrary(hComCtl);

			throw;
		}
	}

	inline BOOL CFrame::LoadRegistryMRUSettings(UINT nMaxMRU /*= 0*/)
	{
		// Load the MRU list from the registry

		assert(!m_tsKeyName.empty()); // KeyName must be set before calling LoadRegistryMRUSettings
		HKEY hKey = NULL;
		BOOL bRet = FALSE;

		try
		{
			m_nMaxMRU = MIN(nMaxMRU, 16);
			std::vector<tString> vMRUEntries;
			tString tsKey = _T("Software\\") + m_tsKeyName + _T("\\Recent Files");

			if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, tsKey.c_str(), 0, KEY_READ, &hKey))
			{
				for (UINT i = 0; i < m_nMaxMRU; ++i)
				{
					DWORD dwType = REG_SZ;
					DWORD dwBufferSize = 0;
					TCHAR szSubKey[10] = _T("");
					wsprintf(szSubKey, _T("File %d\0"), i+1);

					if (ERROR_SUCCESS != RegQueryValueEx(hKey, szSubKey, NULL, &dwType, NULL, &dwBufferSize))
						throw CWinException(_T("RegQueryValueEx failed\n"));

					std::vector<TCHAR> PathName( dwBufferSize, _T('\0') );
					TCHAR* pTCharArray = &PathName[0];

					// load the entry from the registry
					if (ERROR_SUCCESS != RegQueryValueEx(hKey, szSubKey, NULL, &dwType, (LPBYTE)pTCharArray, &dwBufferSize))
						throw CWinException(_T("RegQueryValueEx failed\n"));

					if ( lstrlen( pTCharArray ) )
						vMRUEntries.push_back( pTCharArray );
				}

				// successfully loaded all MRU values, so store them
				m_vMRUEntries = vMRUEntries;
				RegCloseKey(hKey);
				bRet = TRUE;
			}
		}

		catch(const CWinException& e)
		{
			TRACE(_T("Failed to load MRU values from registry\n"));
			e.what();

			if (hKey)
				RegCloseKey(hKey);
		}

		return bRet;
	}

	inline BOOL CFrame::LoadRegistrySettings(LPCTSTR szKeyName)
	{
		assert (NULL != szKeyName);
		m_tsKeyName = szKeyName;

		tString tsKey = _T("Software\\") + m_tsKeyName + _T("\\Frame Settings");
		HKEY hKey = 0;
		BOOL bRet = FALSE;

		try
		{
			if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, tsKey.c_str(), 0, KEY_READ, &hKey))
			{
				DWORD dwType = REG_BINARY;
				DWORD BufferSize = sizeof(DWORD);
				DWORD dwTop, dwLeft, dwWidth, dwHeight, dwStatusBar, dwToolBar;
				if (ERROR_SUCCESS != RegQueryValueEx(hKey, _T("Top"), NULL, &dwType, (LPBYTE)&dwTop, &BufferSize))
					throw CWinException(_T("RegQueryValueEx Failed"));
				if (ERROR_SUCCESS != RegQueryValueEx(hKey, _T("Left"), NULL, &dwType, (LPBYTE)&dwLeft, &BufferSize))
					throw CWinException(_T("RegQueryValueEx Failed"));
				if (ERROR_SUCCESS != RegQueryValueEx(hKey, _T("Width"), NULL, &dwType, (LPBYTE)&dwWidth, &BufferSize))
					throw CWinException(_T("RegQueryValueEx Failed"));
				if (ERROR_SUCCESS != RegQueryValueEx(hKey, _T("Height"), NULL, &dwType, (LPBYTE)&dwHeight, &BufferSize))
					throw CWinException(_T("RegQueryValueEx Failed"));
				if (ERROR_SUCCESS != RegQueryValueEx(hKey, _T("StatusBar"), NULL, &dwType, (LPBYTE)&dwStatusBar, &BufferSize))
					throw CWinException(_T("RegQueryValueEx Failed"));
				if (ERROR_SUCCESS != RegQueryValueEx(hKey, _T("ToolBar"), NULL, &dwType, (LPBYTE)&dwToolBar, &BufferSize))
					throw CWinException(_T("RegQueryValueEx Failed"));

				m_rcPosition.top = dwTop;
				m_rcPosition.left = dwLeft;
				m_rcPosition.bottom = m_rcPosition.top + dwHeight;
				m_rcPosition.right = m_rcPosition.left + dwWidth;
				m_bShowStatusBar = dwStatusBar & 1;
				m_bShowToolBar = dwToolBar & 1;

				RegCloseKey(hKey);
				bRet = TRUE;
			}
		}

		catch (const CWinException& e)
		{
			TRACE(_T("Failed to load values from registry, using defaults!\n"));
			e.what();

			if (hKey)
				RegCloseKey(hKey);
		}

		return bRet;
	}

	inline void CFrame::OnActivate(WPARAM wParam, LPARAM lParam)
	{
		// Do default processing first
		DefWindowProc(WM_ACTIVATE, wParam, lParam);

		if (LOWORD(wParam) == WA_INACTIVE)
		{
			// Save the hwnd of the window which currently has focus
			// (this must be CFrame window itself or a child window
			if (!IsIconic()) m_hOldFocus = ::GetFocus();

			// Send a notification to the view window
			int idCtrl = ::GetDlgCtrlID(m_hOldFocus);
			NMHDR nhdr={0};
			nhdr.hwndFrom = m_hOldFocus;
			nhdr.idFrom = idCtrl;
			nhdr.code = UWM_FRAMELOSTFOCUS;
			if (GetView()->IsWindow())
				GetView()->SendMessage(WM_NOTIFY, (WPARAM)idCtrl, (LPARAM)&nhdr);
		}
		else
		{
			// Now set the focus to the appropriate child window
			if (m_hOldFocus) ::SetFocus(m_hOldFocus);

			// Send a notification to the view window
			int idCtrl = ::GetDlgCtrlID(m_hOldFocus);
			NMHDR nhdr={0};
			nhdr.hwndFrom = m_hOldFocus;
			nhdr.idFrom = idCtrl;
			nhdr.code = UWM_FRAMEGOTFOCUS;
			if (GetView()->IsWindow())
				GetView()->SendMessage(WM_NOTIFY, (WPARAM)idCtrl, (LPARAM)&nhdr);
		}
	}

	inline void CFrame::OnClose()
	{
		// Called in response to a WM_CLOSE message for the frame.
		ShowWindow(SW_HIDE);
		SaveRegistrySettings();

		GetMenuBar().Destroy();
		GetToolBar().Destroy();
		GetReBar().Destroy();
		GetStatusBar().Destroy();
		GetView()->Destroy();
	}

	inline void CFrame::OnCreate()
	{
		// This is called when the frame window is being created.
		// Override this in CMainFrame if you wish to modify what happens here

		// Set the icon
		SetIconLarge(IDW_MAIN);
		SetIconSmall(IDW_MAIN);

		// Set the keyboard accelerators
		m_hAccel = LoadAccelerators(GetApp()->GetResourceHandle(), MAKEINTRESOURCE(IDW_MAIN));
		GetApp()->SetAccelerators(m_hAccel, this);

		// Set the Caption
		SetWindowText(LoadString(IDW_MAIN));

		// Set the theme for the frame elements
		SetTheme();

		// Create the rebar and menubar
		if (IsReBarSupported() && m_bUseReBar)
		{
			// Create the rebar
			GetReBar().Create(this);

			// Create the menu inside rebar
			GetMenuBar().Create(&GetReBar());
			AddMenuBarBand();
		}

		// Setup the menu
		SetFrameMenu(IDW_MAIN);
		UpdateMRUMenu();

		// Create the ToolBar
		if (m_bUseToolBar)
		{
			CreateToolBar();
			ShowToolBar(m_bShowToolBar);
		}
		else
		{
			::CheckMenuItem(GetFrameMenu(), IDW_VIEW_TOOLBAR, MF_UNCHECKED);
			::EnableMenuItem(GetFrameMenu(), IDW_VIEW_TOOLBAR, MF_GRAYED);
		}

		// Create the status bar
		GetStatusBar().Create(this);
		ShowStatusBar(m_bShowStatusBar);

		// Create the view window
		assert(GetView());			// Use SetView in CMainFrame's constructor to set the view window
		GetView()->Create(this);

		// Disable XP themes for the menubar
		if ( m_bUseThemes || (GetWinVersion() < 2600)  )	// themes or WinVersion < Vista
			GetMenuBar().SetWindowTheme(L" ", L" ");

		// Start timer for Status updates
		if (m_bShowIndicatorStatus || m_bShowMenuStatus)
			SetTimer(ID_STATUS_TIMER, 200, NULL);

		// Reposition the child windows
		RecalcLayout();
	}

	inline void CFrame::OnDestroy()
	{
		SetMenu(NULL);
		KillTimer(ID_STATUS_TIMER);
		::PostQuitMessage(0);	// Terminates the application
	}

	inline LRESULT CFrame::OnDrawItem(WPARAM wParam, LPARAM lParam)
	// OwnerDraw is used to render the popup menu items
	{
		LPDRAWITEMSTRUCT pdis = (LPDRAWITEMSTRUCT) lParam;
		if (pdis->CtlType != ODT_MENU)
			return CWnd::WndProcDefault(WM_DRAWITEM, wParam, lParam);

		CRect rc = pdis->rcItem;
		ItemData* pmd = (ItemData*)pdis->itemData;
		CDC* pDrawDC = FromHandle(pdis->hDC);
		MenuTheme tm = GetMenuTheme();

		int Iconx = 16;
		int Icony = 16;
		if (m_himlMenu)	ImageList_GetIconSize(m_himlMenu, &Iconx, &Icony);
		int BarWidth = tm.UseThemes? Iconx + 8 : 0;

		// Draw the side bar
		if (tm.UseThemes)
		{
			CRect rcBar = rc;
			rcBar.right = BarWidth;
			pDrawDC->GradientFill(tm.clrPressed1, tm.clrPressed2, rcBar, TRUE);
		}

		if (pmd->fType & MFT_SEPARATOR)
		{
			// draw separator
			CRect rcSep = rc;
			rcSep.left = BarWidth;
			if (tm.UseThemes)
				pDrawDC->SolidFill(RGB(255,255,255), rcSep);
			else
				pDrawDC->SolidFill(GetSysColor(COLOR_MENU), rcSep);
			rcSep.top += (rc.bottom - rc.top)/2;
			rcSep.left = BarWidth + 2;
			pDrawDC->DrawEdge(rcSep,  EDGE_ETCHED, BF_TOP);
		}
		else
		{
			// draw menu item
			BOOL bDisabled = pdis->itemState & ODS_GRAYED;
			BOOL bSelected = pdis->itemState & ODS_SELECTED;
			BOOL bChecked  = pdis->itemState & ODS_CHECKED;
			CRect rcDraw = rc;

			if ((bSelected) && (!bDisabled))
			{
				// draw selected item background
				if (tm.UseThemes)
				{
					pDrawDC->CreateSolidBrush(tm.clrHot1);
					pDrawDC->CreatePen(PS_SOLID, 1, tm.clrOutline);
					pDrawDC->Rectangle(rcDraw.left, rcDraw.top, rcDraw.right, rcDraw.bottom);
				}
				else
					pDrawDC->SolidFill(GetSysColor(COLOR_HIGHLIGHT), rcDraw);
			}
			else
			{
				// draw non-selected item background
				rcDraw.left = BarWidth;
				if (tm.UseThemes)
					pDrawDC->SolidFill(RGB(255,255,255), rcDraw);
				else
					pDrawDC->SolidFill(GetSysColor(COLOR_MENU), rcDraw);
			}

			if (bChecked)
				DrawCheckmark(pdis, *pDrawDC);
			else
				DrawMenuIcon(pdis, *pDrawDC, bDisabled);

			// Calculate the text rect size
			rc.left  = rc.bottom - rc.top + 2;
			if (_tcschr(pmd->GetItemText(), _T('\t')))
				rc.right -= POST_TEXT_GAP;	// Add POST_TEXT_GAP if the text includes a tab

			// Draw the text
			int iMode = pDrawDC->SetBkMode(TRANSPARENT);
			COLORREF colorText;
			if (tm.UseThemes)
			{
				rc.left += 8;
				colorText = GetSysColor(bDisabled ?  COLOR_GRAYTEXT : COLOR_MENUTEXT);
			}
			else
				colorText = GetSysColor(bDisabled ?  COLOR_GRAYTEXT : bSelected ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT);

			DrawMenuText(*pDrawDC, pmd->GetItemText(), rc, colorText);
			pDrawDC->SetBkMode(iMode); 
		}

		pDrawDC->Detach();	// Optional, deletes GDI objects sooner
		return TRUE;
	}

	inline void CFrame::OnExitMenuLoop()
	{
		if (m_bUseCustomDraw)
		{
			for (UINT nItem = 0; nItem < m_vMenuItemData.size(); ++nItem)
			{
				// Undo OwnerDraw and put the text back
				MENUITEMINFO mii = {0};
				mii.cbSize = GetSizeofMenuItemInfo();

				mii.fMask = MIIM_TYPE | MIIM_DATA;
				mii.fType = m_vMenuItemData[nItem]->fType;
				mii.dwTypeData = m_vMenuItemData[nItem]->GetItemText();
				mii.cch = lstrlen(m_vMenuItemData[nItem]->GetItemText());
				mii.dwItemData = 0;
				::SetMenuItemInfo(m_vMenuItemData[nItem]->hMenu, m_vMenuItemData[nItem]->nPos, TRUE, &mii);
			}

			m_vMenuItemData.clear();
		}
	}

	inline void CFrame::OnHelp()
	{
		// Ensure only one dialog displayed even for multiple hits of the F1 button
		if (!m_AboutDialog.IsWindow())
		{
			// Store the window handle that currently has keyboard focus
			HWND hPrevFocus = ::GetFocus();
			if (hPrevFocus == GetMenuBar())
				hPrevFocus = m_hWnd;

			m_AboutDialog.SetDlgParent(this);
			m_AboutDialog.DoModal();

			::SetFocus(hPrevFocus);
		}
	}

	inline void CFrame::OnInitMenuPopup(WPARAM wParam, LPARAM lParam)
	{
		// The system menu shouldn't be owner drawn
		if (HIWORD(lParam)) return;

		if (m_bUseCustomDraw)
		{
			CMenu* pMenu = FromHandle((HMENU)wParam);

			for (UINT i = 0; i < pMenu->GetMenuItemCount(); ++i)
			{
				MENUITEMINFO mii = {0};
				mii.cbSize = GetSizeofMenuItemInfo();

				TCHAR szMenuItem[MAX_MENU_STRING] = _T("");

				// Use old fashioned MIIM_TYPE instead of MIIM_FTYPE for MS VC6 compatibility
				mii.fMask  = MIIM_TYPE | MIIM_DATA | MIIM_SUBMENU;
				mii.dwTypeData = szMenuItem;
				mii.cch = MAX_MENU_STRING -1;

				// Send message for menu updates
				UINT menuItem = pMenu->GetMenuItemID(i);
				SendMessage(UWM_UPDATE_COMMAND, (WPARAM)menuItem, 0);

				// Specify owner-draw for the menu item type
				if (pMenu->GetMenuItemInfo(i, &mii, TRUE))
				{
					if (0 == mii.dwItemData)
					{
						ItemData* pItem = new ItemData;		// deleted in OnExitMenuLoop
						pItem->hMenu = *pMenu;
						pItem->nPos = i;
						pItem->fType = mii.fType;
						pItem->hSubMenu = mii.hSubMenu;
						mii.fType |= MFT_OWNERDRAW;
						lstrcpyn(pItem->GetItemText(), szMenuItem, MAX_MENU_STRING);
						mii.dwItemData = (DWORD_PTR)pItem;

						m_vMenuItemData.push_back(ItemDataPtr(pItem));		// Store pItem in m_vMenuItemData
						pMenu->SetMenuItemInfo(i, &mii, TRUE); // Store pItem in mii
					}
				}
			}
		}
	}

	inline LRESULT CFrame::OnMeasureItem(WPARAM wParam, LPARAM lParam)
	// Called before the Popup menu is displayed, so that the MEASUREITEMSTRUCT
	//  values can be assigned with the menu item's dimensions.
	{
		LPMEASUREITEMSTRUCT pmis = (LPMEASUREITEMSTRUCT) lParam;
		if (pmis->CtlType != ODT_MENU)
			return CWnd::WndProcDefault(WM_MEASUREITEM, wParam, lParam);

		ItemData* pmd = (ItemData *) pmis->itemData;
		assert(::IsMenu(pmd->hMenu));	// Does itemData contain a valid ItemData struct?
		MenuTheme tm = GetMenuTheme();

		if (pmd->fType & MFT_SEPARATOR)
		{
			pmis->itemHeight = 7;
			pmis->itemWidth  = 0;
		}

		else
		{
			CClientDC DesktopDC(NULL);

			// Get the font used in menu items
			NONCLIENTMETRICS nm = {0};
			nm.cbSize = GetSizeofNonClientMetrics();
			SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(nm), &nm, 0);
			// Default menu items are bold, so take this into account
			if ((int)::GetMenuDefaultItem(pmd->hMenu, TRUE, GMDI_USEDISABLED) != -1)
				nm.lfMenuFont.lfWeight = FW_BOLD;

			TCHAR* pItemText = &(pmd->vItemText[0]);
			DesktopDC.CreateFontIndirect(&nm.lfMenuFont);

			// Calculate the size of the text
			CSize size = DesktopDC.GetTextExtentPoint32(pItemText, lstrlen(pItemText));

			// Calculate the size of the icon
			int Iconx = 16;
			int Icony = 16;
			if (m_himlMenu) ImageList_GetIconSize(m_himlMenu, &Iconx, &Icony);

			pmis->itemHeight = 2+ MAX(MAX(size.cy, GetSystemMetrics(SM_CYMENU)-2), Icony+2);
			pmis->itemWidth = size.cx + MAX(::GetSystemMetrics(SM_CXMENUSIZE), Iconx+2);

			// Allow extra width if the text includes a tab
			if (_tcschr(pItemText, _T('\t')))
				pmis->itemWidth += POST_TEXT_GAP;

			// Allow extra width if the menu item has a sub menu
			if (pmd->hSubMenu)
				pmis->itemWidth += 10;

			// Allow extra width for themed menu
			if (tm.UseThemes)
				pmis->itemWidth += 8;
		}
		 return TRUE;
	}

	inline LRESULT CFrame::OnMenuChar(WPARAM wParam, LPARAM lParam)
	{
		if ((IsMenuBarUsed()) && (LOWORD(wParam)!= VK_SPACE))
		{
			// Activate MenuBar for key pressed with Alt key held down
			GetMenuBar().OnMenuChar(wParam, lParam);
			return -1L;
		}
		return CWnd::WndProcDefault(WM_MENUCHAR, wParam, lParam);
	}

	inline void CFrame::OnMenuSelect(WPARAM wParam, LPARAM lParam)
	{
		// Set the StatusBar text when we hover over a menu
		// Only popup submenus have status strings
		if (m_bShowMenuStatus)
		{
			int nID = LOWORD (wParam);
			CMenu* pMenu = FromHandle((HMENU) lParam);

			if ((pMenu != GetMenu()) && (nID != 0) && !(HIWORD(wParam) & MF_POPUP))
				m_tsStatusText = LoadString(nID);
			else
				m_tsStatusText = _T("Ready");

			SetStatusText();
		}
	}

	inline LRESULT CFrame::OnNotify(WPARAM wParam, LPARAM lParam)
	{
		UNREFERENCED_PARAMETER(wParam);

		switch (((LPNMHDR)lParam)->code)
		{
		case UWM_UNDOCKED:
			m_hOldFocus = 0;
			break;
		case RBN_HEIGHTCHANGE:
			RecalcLayout();
			Invalidate();
			break;
	//	case RBN_LAYOUTCHANGED:
	//		if (GetReBar().GetReBarTheme().UseThemes && GetReBar().GetReBarTheme().BandsLeft)
	//			GetReBar().MoveBandsLeft();
	//		break;
		case RBN_MINMAX:
			if (GetReBar().GetReBarTheme().UseThemes && GetReBar().GetReBarTheme().ShortBands)
				return 1L;	// Supress maximise or minimise rebar band
			break;

		// Display tooltips for the toolbar
		case TTN_GETDISPINFO:
			if (GetToolBar().IsWindow())
			{
				CToolBar* pToolBar = 0;
				if (IsReBarUsed())
				{
					// Get the ToolBar's CWnd
					CWnd* pWnd = FromHandle(GetReBar().HitTest(GetCursorPos()));
					if (pWnd && (lstrcmp(pWnd->GetClassName(), _T("ToolbarWindow32")) == 0))
					{
						pToolBar = (CToolBar*)pWnd;
					}
				}

				if (pToolBar)
				{
					LPNMTTDISPINFO lpDispInfo = (LPNMTTDISPINFO)lParam;
					int iIndex =  pToolBar->HitTest();
					if (iIndex >= 0)
					{
						int nID = pToolBar->GetCommandID(iIndex);
						if (nID > 0)
						{
							m_tsTooltip = LoadString(nID);
							lpDispInfo->lpszText = (LPTSTR)m_tsTooltip.c_str();
						}
						else
							m_tsTooltip = _T("");
					}
				}
			}
			break;
		} // switch LPNMHDR

		return 0L;

	} // CFrame::Onotify(...)

	inline void CFrame::OnSetFocus()
	{
		SetStatusText();
	}

	inline void CFrame::OnSysColorChange()
	{
		// Honour theme color changes
		for (int nBand = 0; nBand <= GetReBar().GetBandCount(); ++nBand)
		{
			GetReBar().SetBandColor(nBand, GetSysColor(COLOR_BTNTEXT), GetSysColor(COLOR_BTNFACE));
		}

		// Update the status bar font and text
		NONCLIENTMETRICS nm = {0};
		nm.cbSize = GetSizeofNonClientMetrics();
		SystemParametersInfo (SPI_GETNONCLIENTMETRICS, 0, &nm, 0);
		LOGFONT lf = nm.lfStatusFont;
		CFont* pFont = FromHandle(CreateFontIndirect(&lf));
		GetStatusBar().SetFont(pFont, FALSE);
		SetStatusText();

		if ((m_bUpdateTheme) && (m_bUseThemes)) SetTheme();

		// Reposition and redraw everything
		RecalcLayout();
		RedrawWindow(NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);

		// Forward the message to the view window
		m_pView->PostMessage(WM_SYSCOLORCHANGE, 0L, 0L);
	}

	inline LRESULT CFrame::OnSysCommand(WPARAM wParam, LPARAM lParam)
	{
		if ((SC_KEYMENU == wParam) && (VK_SPACE != lParam) && IsMenuBarUsed())
		{
			GetMenuBar().OnSysCommand(wParam, lParam);
			return 0L;
		}

		if (SC_MINIMIZE == wParam)
			m_hOldFocus = ::GetFocus();

		return CWnd::WndProcDefault(WM_SYSCOMMAND, wParam, lParam);
	}

	inline void CFrame::OnTimer(WPARAM wParam)
	{
		if (ID_STATUS_TIMER == wParam)
		{
			if (m_bShowMenuStatus)
			{
				// Get the toolbar the point is over
				CToolBar* pToolBar = 0;
				if (IsReBarUsed())
				{
					// Get the ToolBar's CWnd
					CWnd* pWnd = FromHandle(GetReBar().HitTest(GetCursorPos()));
					if (pWnd && (dynamic_cast<CToolBar*>(pWnd)) && !(dynamic_cast<CMenuBar*>(pWnd)))
						pToolBar = (CToolBar*)pWnd;
				}
				else
				{
					CPoint pt = GetCursorPos();
					CWnd* pWnd = WindowFromPoint(GetCursorPos());
					if (pWnd && (dynamic_cast<CToolBar*>(pWnd)))
						pToolBar = (CToolBar*)pWnd;
				}

				if ((pToolBar) && (WindowFromPoint(GetCursorPos()) == pToolBar))
				{
					// Which toolbar button is the mouse cursor hovering over?
					int nButton = pToolBar->HitTest();
					if (nButton >= 0)
					{
						int nID = pToolBar->GetCommandID(nButton);
						// Only update the statusbar if things have changed
						if (nID != m_nOldID)
						{
							if (nID != 0)
								m_tsStatusText = LoadString(nID);
							else
								m_tsStatusText = _T("Ready");

							if (GetStatusBar().IsWindow())
								SetStatusText();
						}
						m_nOldID = nID;
					}
				}
				else
				{
					if (m_nOldID != -1)
					{
						m_tsStatusText = _T("Ready");
						SetStatusText();
					}
					m_nOldID = -1;
				}
			}

			if (m_bShowIndicatorStatus)
				SetStatusIndicators();
		}
	}

	inline void CFrame::OnViewStatusBar()
	{
		m_bShowStatusBar = !m_bShowStatusBar;
		ShowStatusBar(m_bShowStatusBar);
	}

	inline void CFrame::OnViewToolBar()
	{
		m_bShowToolBar = !m_bShowToolBar;
		ShowToolBar(m_bShowToolBar);
	}

  	inline void CFrame::PreCreate(CREATESTRUCT& cs)
	{
		// Set the frame window styles
		cs.style = WS_OVERLAPPEDWINDOW | WS_VISIBLE;

		// Set the original window position
		cs.x  = m_rcPosition.left;
		cs.y  = m_rcPosition.top;
		cs.cx = m_rcPosition.Width();
		cs.cy = m_rcPosition.Height();
	}

	inline void CFrame::PreRegisterClass(WNDCLASS &wc)
	{
		// Set the Window Class
		wc.lpszClassName =  _T("Win32++ Frame");
	}

	inline void CFrame::RecalcLayout()
	{
		CWnd* pView = GetView();
		if ((!pView) || (!pView->GetHwnd()))
			return;

		// Resize the status bar
		if (GetStatusBar().IsWindow() && m_bShowStatusBar)
		{
			GetStatusBar().SetWindowPos(NULL, 0, 0, 0, 0, SWP_SHOWWINDOW);
			GetStatusBar().Invalidate();
			SetStatusText();
		}

		// Resize the rebar or toolbar
		if (IsReBarUsed())
		{
			GetReBar().SendMessage(WM_SIZE, 0L, 0L);
			GetReBar().Invalidate();
		}
		else if (m_bUseToolBar && m_bShowToolBar)
			GetToolBar().SendMessage(TB_AUTOSIZE, 0L, 0L);

		// Resize the View window
		CRect rClient = GetViewRect();
		if ((rClient.bottom - rClient.top) >= 0)
		{
			int x  = rClient.left;
			int y  = rClient.top;
			int cx = rClient.Width();
			int cy = rClient.Height();

			pView->SetWindowPos( NULL, x, y, cx, cy, SWP_SHOWWINDOW|SWP_ASYNCWINDOWPOS );
		}

		// Adjust rebar bands
		if (IsReBarUsed())
		{
			if (GetReBar().GetReBarTheme().UseThemes && GetReBar().GetReBarTheme().BandsLeft)
				GetReBar().MoveBandsLeft();

			if (IsMenuBarUsed())
				SetMenuBarBandSize();
		}
	}

	inline void CFrame::RemoveMRUEntry(LPCTSTR szMRUEntry)
	{
		std::vector<tString>::iterator it;
		for (it = m_vMRUEntries.begin(); it != m_vMRUEntries.end(); ++it)
		{
			if ((*it) == szMRUEntry)
			{
				m_vMRUEntries.erase(it);
				break;
			}
		}

		UpdateMRUMenu();
	}

	inline BOOL CFrame::SaveRegistrySettings()
	{
		// Store the window position in the registry
		if (!m_tsKeyName.empty())
		{
			tString tsKeyName = _T("Software\\") + m_tsKeyName + _T("\\Frame Settings");
			HKEY hKey = NULL;

			try
			{
				if (ERROR_SUCCESS != RegCreateKeyEx(HKEY_CURRENT_USER, tsKeyName.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL))
					throw CWinException(_T("RegCreateKeyEx failed"));

				WINDOWPLACEMENT Wndpl = {0};
				Wndpl.length = sizeof(WINDOWPLACEMENT);

				if (GetWindowPlacement(Wndpl))
				{
					// Get the Frame's window position
					CRect rc = Wndpl.rcNormalPosition;
					DWORD dwTop = MAX(rc.top, 0);
					DWORD dwLeft = MAX(rc.left, 0);
					DWORD dwWidth = MAX(rc.Width(), 100);
					DWORD dwHeight = MAX(rc.Height(), 50);

					if (ERROR_SUCCESS != RegSetValueEx(hKey, _T("Top"), 0, REG_DWORD, (LPBYTE)&dwTop, sizeof(DWORD)))
						throw CWinException(_T("RegSetValueEx failed"));
					if (ERROR_SUCCESS != RegSetValueEx(hKey, _T("Left"), 0, REG_DWORD, (LPBYTE)&dwLeft, sizeof(DWORD)))
						throw CWinException(_T("RegSetValueEx failed"));
					if (ERROR_SUCCESS != RegSetValueEx(hKey, _T("Width"), 0, REG_DWORD, (LPBYTE)&dwWidth, sizeof(DWORD)))
						throw CWinException(_T("RegSetValueEx failed"));
					if (ERROR_SUCCESS != RegSetValueEx(hKey, _T("Height"), 0, REG_DWORD, (LPBYTE)&dwHeight, sizeof(DWORD)))
						throw CWinException(_T("RegSetValueEx failed"));
				}

				// Store the ToolBar and statusbar states
				DWORD dwShowToolBar = m_bShowToolBar;
				DWORD dwShowStatusBar = m_bShowStatusBar;

				if (ERROR_SUCCESS != RegSetValueEx(hKey, _T("ToolBar"), 0, REG_DWORD, (LPBYTE)&dwShowToolBar, sizeof(DWORD)))
					throw CWinException(_T("RegSetValueEx failed"));
				if (ERROR_SUCCESS != RegSetValueEx(hKey, _T("StatusBar"), 0, REG_DWORD, (LPBYTE)&dwShowStatusBar, sizeof(DWORD)))
					throw CWinException(_T("RegSetValueEx failed"));

				RegCloseKey(hKey);
			}

			catch (const CWinException& e)
			{
				TRACE(_T("Failed to save registry settings\n"));

				if (hKey)
				{
					// Roll back the registry changes by deleting this subkey
					RegDeleteKey(HKEY_CURRENT_USER ,tsKeyName.c_str());
					RegCloseKey(hKey);
				}

				e.what();
				return FALSE;
			}

			// Store the MRU entries in the registry
			if (m_nMaxMRU > 0)
			{
				tString tsKeyName = _T("Software\\") + m_tsKeyName + _T("\\Recent Files");
				HKEY hKey = NULL;

				try
				{
					if (ERROR_SUCCESS != RegCreateKeyEx(HKEY_CURRENT_USER, tsKeyName.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL))
						throw CWinException(_T("RegCreateKeyEx failed"));

					for (UINT i = 0; i < m_nMaxMRU; ++i)
					{
						TCHAR szSubKey[10];
						wsprintf(szSubKey, _T("File %d\0"), i+1);
						tString tsPathName;
						if (i < m_vMRUEntries.size())
							tsPathName = m_vMRUEntries[i];

						if (ERROR_SUCCESS != RegSetValueEx(hKey, szSubKey, 0, REG_SZ, (LPBYTE)tsPathName.c_str(), (1 + lstrlen(tsPathName.c_str()))*sizeof(TCHAR)))
							throw CWinException(_T("RegSetValueEx failed"));
					}

					RegCloseKey(hKey);
				}

				catch (const CWinException& e)
				{
					TRACE(_T("Failed to save registry MRU settings\n"));

					if (hKey)
					{
						// Roll back the registry changes by deleting this subkey
						RegDeleteKey(HKEY_CURRENT_USER ,tsKeyName.c_str());
						RegCloseKey(hKey);
					}

					e.what();
					return FALSE;
				}
			}
		}

		return TRUE;
	}

	inline void CFrame::SetFrameMenu(INT ID_MENU)
	{
		// Sets the frame's menu from a Resouce ID.
		// A resource ID of 0 removes the menu from the frame.
		HMENU hMenu = 0;
		if (ID_MENU != 0)
		{
		// Sets the frame's menu from a resource ID.
			hMenu = ::LoadMenu(GetApp()->GetResourceHandle(), MAKEINTRESOURCE(ID_MENU));
			assert (hMenu);
		}

		SetFrameMenu(hMenu);
 	}

	inline void CFrame::SetFrameMenu(HMENU hMenu)
	{
		// Sets the frame's menu from a HMENU.
		m_Menu.Attach(hMenu);

		if (IsMenuBarUsed())
		{
			GetMenuBar().SetMenu(GetFrameMenu());
			BOOL bShow = (hMenu != NULL);	// boolean expression
			ShowMenu(bShow);
		}
		else
			SetMenu(&m_Menu);
 	}

	inline UINT CFrame::SetMenuIcons(const std::vector<UINT>& MenuData, COLORREF crMask, UINT ToolBarID, UINT ToolBarDisabledID)
	{
		// Remove any existing menu icons
		if (m_himlMenu) ImageList_Destroy(m_himlMenu);
		if (m_himlMenuDis) ImageList_Destroy(m_himlMenuDis);
		m_himlMenu = NULL;
		m_himlMenuDis = NULL;
		m_vMenuIcons.clear();

		// Exit if no ToolBarID is specified
		if (ToolBarID == 0) return 0;

		// Add the menu icons from the bitmap IDs
		return AddMenuIcons(MenuData, crMask, ToolBarID, ToolBarDisabledID);
	}

	inline void CFrame::SetMenuBarBandSize()
	{
		// Sets the minimum width of the MenuBar band to the width of the rebar
		// This prevents other bands from moving to this MenuBar's row.

		CRect rcClient = GetClientRect();
		CReBar& RB = GetReBar();
		int nBand = RB.GetBand(GetMenuBar());
		CRect rcBorder = RB.GetBandBorders(nBand);

		REBARBANDINFO rbbi = {0};
		rbbi.fMask = RBBIM_CHILDSIZE | RBBIM_SIZE;
		RB.GetBandInfo(nBand, rbbi);

		int Width;
		if ((GetReBar().GetReBarTheme().UseThemes) && (GetReBar().GetReBarTheme().LockMenuBand))
			Width = rcClient.Width() - rcBorder.Width() - 2;
		else
			Width = GetMenuBar().GetMaxSize().cx;

		rbbi.cxMinChild = Width;
		rbbi.cx         = Width;

		RB.SetBandInfo(nBand, rbbi);
	}

	inline void CFrame::SetMenuTheme(MenuTheme& Theme)
	{
		m_ThemeMenu.UseThemes   = Theme.UseThemes;
		m_ThemeMenu.clrHot1     = Theme.clrHot1;
		m_ThemeMenu.clrHot2     = Theme.clrHot2;
		m_ThemeMenu.clrPressed1 = Theme.clrPressed1;
		m_ThemeMenu.clrPressed2 = Theme.clrPressed2;
		m_ThemeMenu.clrOutline  = Theme.clrOutline;

		GetMenuBar().SetMenuBarTheme(Theme); // Sets the theme for MenuBar buttons
		Invalidate();
	}

	inline void CFrame::SetStatusIndicators()
	{
		if (::IsWindow(GetStatusBar()))
		{
			LPCTSTR Status1 = (::GetKeyState(VK_CAPITAL) & 0x0001)? _T("\tCAP") : _T("");
			LPCTSTR Status2 = (::GetKeyState(VK_NUMLOCK) & 0x0001)? _T("\tNUM") : _T("");
			LPCTSTR Status3 = (::GetKeyState(VK_SCROLL)  & 0x0001)? _T("\tSCRL"): _T("");

			// Only update indictors if the text has changed
			if (Status1 != m_OldStatus[0]) 	GetStatusBar().SetPartText(1, (Status1));
			if (Status2 != m_OldStatus[1])  GetStatusBar().SetPartText(2, (Status2));
			if (Status3 != m_OldStatus[2])  GetStatusBar().SetPartText(3, (Status3));

			m_OldStatus[0] = Status1;
			m_OldStatus[1] = Status2;
			m_OldStatus[2] = Status3;
		}
	}

	inline void CFrame::SetStatusText()
	{
		if (::IsWindow(GetStatusBar()))
		{
			// Calculate the width of the text indicators
			CClientDC dcStatus(&GetStatusBar());
			CSize csCAP  = dcStatus.GetTextExtentPoint32(_T("\tCAP"), lstrlen(_T("\tCAP")));
			CSize csNUM  = dcStatus.GetTextExtentPoint32(_T("\tNUM"), lstrlen(_T("\tNUM")));
			CSize csSCRL = dcStatus.GetTextExtentPoint32(_T("\tSCRL "), lstrlen(_T("\tSCRL ")));

			// Get the coordinates of the parent window's client area.
			CRect rcClient = GetClientRect();
			int width = MAX(300, rcClient.right);

			if (m_bShowIndicatorStatus)
			{
				// Create 4 panes
				GetStatusBar().SetPartWidth(0, width - (csCAP.cx+csNUM.cx+csSCRL.cx+20));
				GetStatusBar().SetPartWidth(1, csCAP.cx);
				GetStatusBar().SetPartWidth(2, csNUM.cx);
				GetStatusBar().SetPartWidth(3, csSCRL.cx);

				SetStatusIndicators();
			}

			// Place text in the 1st pane
			GetStatusBar().SetPartText(0, m_tsStatusText.c_str());
		}
	}

	inline void CFrame::SetTheme()
	{
		// Note: To modify theme colors, override this function in CMainframe,
		//        and make any modifications there.

		// Avoid themes if using less than 16 bit colors
		CClientDC DesktopDC(NULL);
		if (DesktopDC.GetDeviceCaps(BITSPIXEL) < 16)
			m_bUseThemes = FALSE;

		BOOL T = TRUE;
		BOOL F = FALSE;

		if (m_bUseThemes)
		{
			// Set a flag redo SetTheme when the theme changes
			m_bUpdateTheme = TRUE;

			// Detect the XP theme name
			WCHAR Name[30] = L"";
			HMODULE hMod = ::LoadLibrary(_T("uxtheme.dll"));
			if(hMod)
			{
				typedef HRESULT (__stdcall *PFNGETCURRENTTHEMENAME)(LPWSTR pszThemeFileName, int cchMaxNameChars,
					LPWSTR pszColorBuff, int cchMaxColorChars, LPWSTR pszSizeBuff, int cchMaxSizeChars);

				PFNGETCURRENTTHEMENAME pfn = (PFNGETCURRENTTHEMENAME)GetProcAddress(hMod, "GetCurrentThemeName");

				(*pfn)(0, 0, Name, 30, 0, 0);

				::FreeLibrary(hMod);
			}

			enum Themetype{ Modern, Grey, Blue, Silver, Olive };

			int Theme = Grey;
			if (GetWinVersion() < 2600) // Not for Vista and above
			{
				if (0 == wcscmp(L"NormalColor", Name))	Theme = Blue;
				if (0 == wcscmp(L"Metallic", Name))		Theme = Silver;
				if (0 == wcscmp(L"HomeStead", Name))	Theme = Olive;
			}
			else
				Theme = Modern;

			switch (Theme)
			{
			case Modern:
				{
					ToolBarTheme tt = {T, RGB(180, 250, 255), RGB(140, 190, 255), RGB(150, 220, 255), RGB(80, 100, 255), RGB(127, 127, 255)};
					ReBarTheme tr = {T, RGB(220, 225, 250), RGB(240, 242, 250), RGB(240, 240, 250), RGB(180, 200, 230), F, T, T, T, T, F};
					MenuTheme tm = {T, RGB(180, 250, 255), RGB(140, 190, 255), RGB(240, 250, 255), RGB(120, 170, 220), RGB(127, 127, 255)};

					GetToolBar().SetToolBarTheme(tt);
					SetMenuTheme(tm); // Sets the theme for popup menus and MenuBar

					GetReBar().SetReBarTheme(tr);
				}
				break;

			case Grey:	// A color scheme suitable for 16 bit colors. Suitable for Windows older than XP.
				{
					ToolBarTheme tt = {T, RGB(182, 189, 210), RGB(182, 189, 210), RGB(133, 146, 181), RGB(133, 146, 181), RGB(10, 36, 106)};
					ReBarTheme tr = {T, RGB(212, 208, 200), RGB(212, 208, 200), RGB(230, 226, 222), RGB(220, 218, 208), F, T, T, T, T, F};
					MenuTheme tm = {T, RGB(182, 189, 210), RGB( 182, 189, 210), RGB(200, 196, 190), RGB(200, 196, 190), RGB(100, 100, 100)};

					GetToolBar().SetToolBarTheme(tt);
					SetMenuTheme(tm); // Sets the theme for popup menus and MenuBar

					GetReBar().SetReBarTheme(tr);
				}
				break;
			case Blue:
				{
					// Used for XP default (blue) color scheme
					ToolBarTheme tt = {T, RGB(255, 230, 190), RGB(255, 190, 100), RGB(255, 140, 40), RGB(255, 180, 80), RGB(192, 128, 255)};
					ReBarTheme tr = {T, RGB(150,190,245), RGB(196,215,250), RGB(220,230,250), RGB( 70,130,220), F, T, T, T, T, F};
					MenuTheme tm = {T, RGB(255, 230, 190), RGB(255, 190, 100), RGB(220,230,250), RGB(150,190,245), RGB(128, 128, 200)};

					GetToolBar().SetToolBarTheme(tt);
					SetMenuTheme(tm); // Sets the theme for popup menus and MenuBar

					GetReBar().SetReBarTheme(tr);
				}
				break;

			case Silver:
				{
					// Used for XP Silver color scheme
					ToolBarTheme tt = {T, RGB(192, 210, 238), RGB(192, 210, 238), RGB(152, 181, 226), RGB(152, 181, 226), RGB(49, 106, 197)};
					ReBarTheme tr = {T, RGB(225, 220, 240), RGB(240, 240, 245), RGB(245, 240, 255), RGB(160, 155, 180), F, T, T, T, T, F};
					MenuTheme tm = {T, RGB(196, 215, 250), RGB( 120, 180, 220), RGB(240, 240, 245), RGB(170, 165, 185), RGB(128, 128, 150)};

					GetToolBar().SetToolBarTheme(tt);
					SetMenuTheme(tm); // Sets the theme for popup menus and MenuBar

					GetReBar().SetReBarTheme(tr);
				}
				break;

			case Olive:
				{
					// Used for XP Olive color scheme
					ReBarTheme tr = {T, RGB(215, 216, 182), RGB(242, 242, 230), RGB(249, 255, 227), RGB(178, 191, 145), F, T, T, T, T, F};
					ToolBarTheme tt = {T, RGB(255, 230, 190), RGB(255, 190, 100), RGB(255, 140, 40), RGB(255, 180, 80), RGB(200, 128, 128)};
					MenuTheme tm = {T, RGB(255, 230, 190), RGB(255, 190, 100), RGB(249, 255, 227), RGB(178, 191, 145), RGB(128, 128, 128)};

					GetToolBar().SetToolBarTheme(tt);
					SetMenuTheme(tm); // Sets the theme for popup menus and MenuBar

					GetReBar().SetReBarTheme(tr);
				}
				break;
			}
		}
		else
		{
			// Use a classic style by default
			ReBarTheme tr = {T, 0, 0, 0, 0, F, T, T, F, F, F};
			GetReBar().SetReBarTheme(tr);
		}

		RecalcLayout();
	}

	inline void CFrame::SetToolBarImages(COLORREF crMask, UINT ToolBarID, UINT ToolBarHotID, UINT ToolBarDisabledID)
	// Either sets the imagelist or adds/replaces bitmap depending on ComCtl32.dll version
	// Assumes the width of the button image = bitmap_size / buttons
	// Assumes buttons have been already been added via AdddToolBarButton
	// The colour mask is ignored for 32bit bitmaps, but is required for 24bit bitmaps
	// The colour mask is often grey RGB(192,192,192) or magenta (255,0,255)
	// The color mask is ignored for 32bit bitmap resources
	// The Hot and disabled bitmap resources can be 0
	{
		GetToolBar().SetImages(crMask, ToolBarID, ToolBarHotID, ToolBarDisabledID);
	}

	inline void CFrame::SetupToolBar()
	{
		// Use this function to set the Resource IDs for the toolbar(s).

/*		// Set the Resource IDs for the toolbar buttons
		AddToolBarButton( IDM_FILE_NEW   );
		AddToolBarButton( IDM_FILE_OPEN  );
		AddToolBarButton( IDM_FILE_SAVE  );
		AddToolBarButton( 0 );				// Separator
		AddToolBarButton( IDM_EDIT_CUT   );
		AddToolBarButton( IDM_EDIT_COPY  );
		AddToolBarButton( IDM_EDIT_PASTE );
		AddToolBarButton( 0 );				// Separator
		AddToolBarButton( IDM_FILE_PRINT );
		AddToolBarButton( 0 );				// Separator
		AddToolBarButton( IDM_HELP_ABOUT );
*/
	}

	inline void CFrame::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 CMainFrame's constructor to set the view window
				GetView()->Create(this);
				RecalcLayout();
			}
		}
	}

	inline void CFrame::ShowMenu(BOOL bShow)
	{
		if (bShow)
		{
			if (IsReBarUsed())
				GetReBar().SendMessage(RB_SHOWBAND, GetReBar().GetBand(GetMenuBar()), TRUE);
			else
				SetMenu(&m_Menu);
		}
		else
		{
			if (IsReBarUsed())
				GetReBar().SendMessage(RB_SHOWBAND, GetReBar().GetBand(GetMenuBar()), FALSE);
			else
				SetMenu(NULL);
		}

		if (GetReBar().IsWindow())
		{
			if (GetReBar().GetReBarTheme().UseThemes && GetReBar().GetReBarTheme().BandsLeft)
				GetReBar().MoveBandsLeft();
		}

		// Reposition the Windows
		RecalcLayout();
	}



	inline void CFrame::ShowStatusBar(BOOL bShow)
	{
		if (bShow)
		{
			m_Menu.CheckMenuItem(IDW_VIEW_STATUSBAR, MF_CHECKED);
			GetStatusBar().ShowWindow(SW_SHOW);
		}
		else
		{
			m_Menu.CheckMenuItem(IDW_VIEW_STATUSBAR, MF_UNCHECKED);
			GetStatusBar().ShowWindow(SW_HIDE);
		}

		// Reposition the Windows
		RecalcLayout();
	}

	inline void CFrame::ShowToolBar(BOOL bShow)
	{
		if (bShow)
		{
			m_Menu.CheckMenuItem(IDW_VIEW_TOOLBAR, MF_CHECKED);
			if (IsReBarUsed())
				GetReBar().SendMessage(RB_SHOWBAND, GetReBar().GetBand(GetToolBar()), TRUE);
			else
				GetToolBar().ShowWindow(SW_SHOW);
		}
		else
		{
			m_Menu.CheckMenuItem(IDW_VIEW_TOOLBAR, MF_UNCHECKED);
			if (IsReBarUsed())
				GetReBar().SendMessage(RB_SHOWBAND, GetReBar().GetBand(GetToolBar()), FALSE);
			else
				GetToolBar().ShowWindow(SW_HIDE);
		}

		if (GetReBar().IsWindow())
		{
			if (GetReBar().GetReBarTheme().UseThemes && GetReBar().GetReBarTheme().BandsLeft)
				GetReBar().MoveBandsLeft();
		}

		// Reposition the Windows
		RecalcLayout();
	}

	inline void CFrame::UpdateMRUMenu()
	{
		if (0 >= m_nMaxMRU) return;

		// Set the text for the MRU Menu
		tString tsMRUArray[16];
		UINT MaxMRUArrayIndex = 0;
		if (m_vMRUEntries.size() > 0)
		{
			for (UINT n = 0; ((n < m_vMRUEntries.size()) && (n <= m_nMaxMRU)); ++n)
			{
				tsMRUArray[n] = m_vMRUEntries[n];
				if (tsMRUArray[n].length() > MAX_MENU_STRING - 10)
				{
					// Truncate the string if its too long
					tsMRUArray[n].erase(0, tsMRUArray[n].length() - MAX_MENU_STRING +10);
					tsMRUArray[n] = _T("... ") + tsMRUArray[n];
				}

				// Prefix the string with its number
				TCHAR tVal[5];
				wsprintf(tVal, _T("%d "), n+1);
				tsMRUArray[n] = tVal + tsMRUArray[n];
				MaxMRUArrayIndex = n;
			}
		}
		else
		{
			tsMRUArray[0] = _T("Recent Files");
		}

		// Set MRU menu items
		MENUITEMINFO mii = {0};
		mii.cbSize = GetSizeofMenuItemInfo();

		int nFileItem = 0;  // We place the MRU items under the left most menu item
		CMenu* pFileMenu = GetFrameMenu().GetSubMenu(nFileItem);

		if (pFileMenu)
		{
			// Remove all but the first MRU Menu entry
			for (UINT u = IDW_FILE_MRU_FILE2; u <= IDW_FILE_MRU_FILE1 +16; ++u)
			{
				pFileMenu->DeleteMenu(u, MF_BYCOMMAND);
			}

			int MaxMRUIndex = (int)MIN(MaxMRUArrayIndex, m_nMaxMRU);

			for (int index = MaxMRUIndex; index >= 0; --index)
			{
				mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
				mii.fState = (0 == m_vMRUEntries.size())? MFS_GRAYED : 0;
				mii.fType = MFT_STRING;
				mii.wID = IDW_FILE_MRU_FILE1 + index;
				mii.dwTypeData = (LPTSTR)tsMRUArray[index].c_str();

				BOOL bResult;
				if (index == MaxMRUIndex)
					// Replace the last MRU entry first
					bResult = pFileMenu->SetMenuItemInfo(IDW_FILE_MRU_FILE1, &mii, FALSE);
				else
					// Insert the other MRU entries next
					bResult = pFileMenu->InsertMenuItem(IDW_FILE_MRU_FILE1 + index + 1, &mii, FALSE);

				if (!bResult)
				{
					TRACE(_T("Failed to set MRU menu item\n"));
					break;
				}
			}
		}

		DrawMenuBar();
	}

	inline LRESULT CFrame::WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam)
	{
		switch (uMsg)
		{
		case WM_ACTIVATE:
			OnActivate(wParam, lParam);
			return 0L;
		case WM_CLOSE:
			OnClose();
			break;
		case WM_DESTROY:
			OnDestroy();
			return 0L;
		case WM_ERASEBKGND:
			return 0L;
		case WM_HELP:
			OnHelp();
			return 0L;
		case WM_MENUCHAR:
			return OnMenuChar(wParam, lParam);
		case WM_MENUSELECT:
			OnMenuSelect(wParam, lParam);
			return 0L;
		case WM_SETFOCUS:
			OnSetFocus();
			break;
		case WM_SIZE:
			RecalcLayout();
			return 0L;
		case WM_SYSCOLORCHANGE:
			// Changing themes trigger this
			OnSysColorChange();
			return 0L;
		case WM_SYSCOMMAND:
			return OnSysCommand(wParam, lParam);
		case WM_TIMER:
			OnTimer(wParam);
			return 0L;
		case WM_DRAWITEM:
			// Owner draw menu items
			return OnDrawItem(wParam, lParam);
		case WM_INITMENUPOPUP:
			OnInitMenuPopup(wParam, lParam);
			break;
		case WM_MEASUREITEM:
			return OnMeasureItem(wParam, lParam);
		case WM_EXITMENULOOP:
			OnExitMenuLoop();
			break;
		case UWM_GETMENUTHEME:
			{
				MenuTheme& tm = GetMenuTheme();
				return (LRESULT)&tm;
			}
		case UWM_GETREBARTHEME:
			{
				ReBarTheme& rm = GetReBarTheme();
				return (LRESULT)&rm;
			}
		case UWM_GETTOOLBARTHEME:
			{
				ToolBarTheme& tt = GetToolBarTheme();
				return (LRESULT)&tt;
			}
		} // switch uMsg

		return CWnd::WndProcDefault(uMsg, wParam, lParam);
	} // LRESULT CFrame::WndProcDefault(...)


} // namespace Win32xx

#endif // _WIN32XX_FRAME_H_