1659 lines
		
	
	
		
			44 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1659 lines
		
	
	
		
			44 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// 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.
 | 
						|
//
 | 
						|
////////////////////////////////////////////////////////
 | 
						|
 | 
						|
 | 
						|
///////////////////////////////////////////////////////
 | 
						|
// tab.h
 | 
						|
//  Declaration of the CTab and CMDITab classes
 | 
						|
 | 
						|
#ifndef _WIN32XX_TAB_H_
 | 
						|
#define _WIN32XX_TAB_H_
 | 
						|
 | 
						|
#include "wincore.h"
 | 
						|
#include "dialog.h"
 | 
						|
#include "gdi.h"
 | 
						|
#include "default_resource.h"
 | 
						|
 | 
						|
namespace Win32xx
 | 
						|
{
 | 
						|
 | 
						|
	struct TabPageInfo
 | 
						|
	{
 | 
						|
		TCHAR szTabText[MAX_MENU_STRING];
 | 
						|
		int iImage;			// index of this tab's image
 | 
						|
		int idTab;			// identifier for this tab (optional)
 | 
						|
		CWnd* pView;		// pointer to the view window
 | 
						|
	};
 | 
						|
 | 
						|
	class CTab : public CWnd
 | 
						|
	{
 | 
						|
	protected:
 | 
						|
		// Declaration of the CSelectDialog class, a nested class of CTab
 | 
						|
		// It creates the dialog to choose which tab to activate
 | 
						|
		class CSelectDialog : public CDialog
 | 
						|
		{
 | 
						|
		public:
 | 
						|
			CSelectDialog(LPCDLGTEMPLATE lpTemplate, CWnd* pParent = NULL);
 | 
						|
			virtual ~CSelectDialog() {}
 | 
						|
			virtual void AddItem(LPCTSTR szString);
 | 
						|
			virtual BOOL IsTab() const { return FALSE; }
 | 
						|
 | 
						|
		protected:
 | 
						|
			virtual BOOL OnInitDialog();
 | 
						|
			virtual void OnOK();
 | 
						|
			virtual void OnCancel() { EndDialog(-2); }
 | 
						|
 | 
						|
		private:
 | 
						|
			CSelectDialog(const CSelectDialog&);				// Disable copy construction
 | 
						|
			CSelectDialog& operator = (const CSelectDialog&); // Disable assignment operator
 | 
						|
 | 
						|
			std::vector<tString> m_vItems;
 | 
						|
			int IDC_LIST;
 | 
						|
 | 
						|
		};
 | 
						|
	public:
 | 
						|
		CTab();
 | 
						|
		virtual ~CTab();
 | 
						|
		virtual int  AddTabPage(WndPtr pView, LPCTSTR szTabText, HICON hIcon, UINT idTab);
 | 
						|
		virtual int  AddTabPage(WndPtr pView, LPCTSTR szTabText, int nID_Icon, UINT idTab = 0);
 | 
						|
		virtual int  AddTabPage(WndPtr pView, LPCTSTR szTabText);
 | 
						|
		virtual CRect GetCloseRect() const;
 | 
						|
		virtual CRect GetListRect() const;
 | 
						|
		virtual HMENU GetListMenu();
 | 
						|
		virtual BOOL GetTabsAtTop() const;
 | 
						|
		virtual int  GetTabIndex(CWnd* pWnd) const;
 | 
						|
		virtual TabPageInfo GetTabPageInfo(UINT nTab) const;
 | 
						|
		virtual int GetTextHeight() const;
 | 
						|
		virtual void RecalcLayout();
 | 
						|
		virtual void RemoveTabPage(int nPage);
 | 
						|
		virtual void SelectPage(int nPage);
 | 
						|
		virtual void SetFixedWidth(BOOL bEnabled);
 | 
						|
		virtual void SetOwnerDraw(BOOL bEnabled);
 | 
						|
		virtual void SetShowButtons(BOOL bShow);
 | 
						|
		virtual void SetTabIcon(int i, HICON hIcon);
 | 
						|
		virtual void SetTabsAtTop(BOOL bTop);
 | 
						|
		virtual void SetTabText(UINT nTab, LPCTSTR szText);
 | 
						|
		virtual void SwapTabs(UINT nTab1, UINT nTab2);
 | 
						|
 | 
						|
		// Attributes
 | 
						|
		std::vector <TabPageInfo>& GetAllTabs() const { return (std::vector <TabPageInfo>&) m_vTabPageInfo; }
 | 
						|
		HIMAGELIST GetImageList() const { return m_himlTab; }
 | 
						|
		BOOL GetShowButtons() const { return m_bShowButtons; }
 | 
						|
		int GetTabHeight() const { return m_nTabHeight; }
 | 
						|
		CWnd* GetActiveView() const		{ return m_pActiveView; }
 | 
						|
		void SetTabHeight(int nTabHeight) { m_nTabHeight = nTabHeight; NotifyChanged();}
 | 
						|
 | 
						|
		// Wrappers for Win32 Macros
 | 
						|
		void AdjustRect(BOOL fLarger, RECT *prc) const;
 | 
						|
		int  GetCurFocus() const;
 | 
						|
		int  GetCurSel() const;
 | 
						|
		BOOL GetItem(int iItem, LPTCITEM pitem) const;
 | 
						|
		int  GetItemCount() const;
 | 
						|
		int  HitTest(TCHITTESTINFO& info) const;
 | 
						|
		void SetCurFocus(int iItem) const;
 | 
						|
		int  SetCurSel(int iItem) const;
 | 
						|
		DWORD SetItemSize(int cx, int cy) const;
 | 
						|
		int  SetMinTabWidth(int cx) const;
 | 
						|
		void SetPadding(int cx, int cy) const;
 | 
						|
 | 
						|
	protected:
 | 
						|
		virtual void	DrawCloseButton(CDC& DrawDC);
 | 
						|
		virtual void	DrawListButton(CDC& DrawDC);
 | 
						|
		virtual void	DrawTabs(CDC& dcMem);
 | 
						|
		virtual void	DrawTabBorders(CDC& dcMem, CRect& rcTab);
 | 
						|
		virtual void    OnCreate();
 | 
						|
		virtual void    OnLButtonDown(WPARAM wParam, LPARAM lParam);
 | 
						|
		virtual void    OnLButtonUp(WPARAM wParam, LPARAM lParam);
 | 
						|
		virtual void    OnMouseLeave(WPARAM wParam, LPARAM lParam);
 | 
						|
		virtual void    OnMouseMove(WPARAM wParam, LPARAM lParam);
 | 
						|
		virtual LRESULT OnNCHitTest(WPARAM wParam, LPARAM lParam);
 | 
						|
		virtual LRESULT OnNotifyReflect(WPARAM wParam, LPARAM lParam);
 | 
						|
		virtual void	NotifyChanged();
 | 
						|
		virtual void	Paint();
 | 
						|
		virtual void    PreCreate(CREATESTRUCT& cs);
 | 
						|
		virtual void	PreRegisterClass(WNDCLASS &wc);
 | 
						|
		virtual void    SetTabSize();
 | 
						|
		virtual void	ShowListDialog();
 | 
						|
		virtual void	ShowListMenu();
 | 
						|
		virtual LRESULT WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam);
 | 
						|
 | 
						|
	private:
 | 
						|
		CTab(const CTab&);				// Disable copy construction
 | 
						|
		CTab& operator = (const CTab&); // Disable assignment operator
 | 
						|
 | 
						|
		SIZE  GetMaxTabSize() const;
 | 
						|
		void ShowActiveView(CWnd* pView);
 | 
						|
 | 
						|
		std::vector<TabPageInfo> m_vTabPageInfo;
 | 
						|
		std::vector<WndPtr> m_vTabViews;
 | 
						|
		CFont m_Font;
 | 
						|
		HIMAGELIST m_himlTab;
 | 
						|
		HMENU m_hListMenu;
 | 
						|
		CWnd* m_pActiveView;
 | 
						|
		BOOL m_bShowButtons;	// Show or hide the close and list button
 | 
						|
		BOOL m_IsTracking;
 | 
						|
		BOOL m_IsClosePressed;
 | 
						|
		BOOL m_IsListPressed;
 | 
						|
		BOOL m_IsListMenuActive;
 | 
						|
		int m_nTabHeight;
 | 
						|
	};
 | 
						|
 | 
						|
	////////////////////////////////////////
 | 
						|
	// Declaration of the CTabbedMDI class
 | 
						|
	class CTabbedMDI : public CWnd
 | 
						|
	{
 | 
						|
	public:
 | 
						|
		CTabbedMDI();
 | 
						|
		virtual ~CTabbedMDI();
 | 
						|
		virtual CWnd* AddMDIChild(CWnd* pView, LPCTSTR szTabText, int idMDIChild = 0);
 | 
						|
		virtual void  CloseActiveMDI();
 | 
						|
		virtual void  CloseAllMDIChildren();
 | 
						|
		virtual void  CloseMDIChild(int nTab);
 | 
						|
		virtual CWnd* GetActiveMDIChild() const;
 | 
						|
		virtual int	  GetActiveMDITab() const;
 | 
						|
		virtual CWnd* GetMDIChild(int nTab) const;
 | 
						|
		virtual int   GetMDIChildCount() const;
 | 
						|
		virtual int   GetMDIChildID(int nTab) const;
 | 
						|
		virtual LPCTSTR GetMDIChildTitle(int nTab) const;
 | 
						|
		virtual HMENU GetListMenu() const { return GetTab().GetListMenu(); }
 | 
						|
		virtual CTab& GetTab() const	{return (CTab&)m_Tab;}
 | 
						|
		virtual BOOL LoadRegistrySettings(tString tsRegistryKeyName);
 | 
						|
		virtual void RecalcLayout();
 | 
						|
		virtual BOOL SaveRegistrySettings(tString tsRegistryKeyName);
 | 
						|
		virtual void SetActiveMDIChild(CWnd* pWnd);
 | 
						|
		virtual void SetActiveMDITab(int nTab);
 | 
						|
 | 
						|
	protected:
 | 
						|
		virtual HWND    Create(CWnd* pParent);
 | 
						|
		virtual CWnd*   NewMDIChildFromID(int idMDIChild);
 | 
						|
		virtual void	OnCreate();
 | 
						|
		virtual void    OnDestroy(WPARAM wParam, LPARAM lParam);
 | 
						|
		virtual LRESULT OnNotify(WPARAM wParam, LPARAM lParam);
 | 
						|
		virtual void    OnWindowPosChanged(WPARAM wParam, LPARAM lParam);
 | 
						|
		virtual LRESULT WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam);
 | 
						|
 | 
						|
	private:
 | 
						|
		CTabbedMDI(const CTabbedMDI&);				// Disable copy construction
 | 
						|
		CTabbedMDI& operator = (const CTabbedMDI&); // Disable assignment operator
 | 
						|
 | 
						|
		CTab m_Tab;
 | 
						|
	};
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
						|
 | 
						|
 | 
						|
namespace Win32xx
 | 
						|
{
 | 
						|
 | 
						|
	/////////////////////////////////////////////////////////////
 | 
						|
	// Definitions for the CSelectDialog class nested within CTab
 | 
						|
	//
 | 
						|
	inline CTab::CSelectDialog::CSelectDialog(LPCDLGTEMPLATE lpTemplate, CWnd* pParent) :
 | 
						|
					CDialog(lpTemplate, pParent), IDC_LIST(121)
 | 
						|
	{
 | 
						|
	}
 | 
						|
 | 
						|
	inline BOOL CTab::CSelectDialog::OnInitDialog()
 | 
						|
	{
 | 
						|
		for (UINT u = 0; u < m_vItems.size(); ++u)
 | 
						|
		{
 | 
						|
			SendDlgItemMessage(IDC_LIST, LB_ADDSTRING, 0, (LPARAM) m_vItems[u].c_str());
 | 
						|
		}
 | 
						|
 | 
						|
		return true;
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTab::CSelectDialog::AddItem(LPCTSTR szString)
 | 
						|
	{
 | 
						|
		m_vItems.push_back(szString);
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTab::CSelectDialog::OnOK()
 | 
						|
	{
 | 
						|
		int iSelect = (int)SendDlgItemMessage(IDC_LIST, LB_GETCURSEL, 0, 0);
 | 
						|
		if (iSelect != LB_ERR) 
 | 
						|
			EndDialog(iSelect);
 | 
						|
		else
 | 
						|
			EndDialog(-2);
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
	//////////////////////////////////////////////////////////
 | 
						|
	// Definitions for the CTab class
 | 
						|
	//
 | 
						|
	inline CTab::CTab() : m_hListMenu(NULL), m_pActiveView(NULL), m_bShowButtons(FALSE), m_IsTracking(FALSE), m_IsClosePressed(FALSE),
 | 
						|
							m_IsListPressed(FALSE), m_IsListMenuActive(FALSE), m_nTabHeight(0)
 | 
						|
	{
 | 
						|
		// Create and assign the image list
 | 
						|
		m_himlTab = ImageList_Create(16, 16, ILC_MASK|ILC_COLOR32, 0, 0);
 | 
						|
 | 
						|
		// Set the tab control's font
 | 
						|
		NONCLIENTMETRICS info = {0};
 | 
						|
		info.cbSize = GetSizeofNonClientMetrics();
 | 
						|
		SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0);
 | 
						|
		m_Font.CreateFontIndirect(&info.lfStatusFont);
 | 
						|
	}
 | 
						|
 | 
						|
	inline CTab::~CTab()
 | 
						|
	{
 | 
						|
		ImageList_Destroy(m_himlTab);
 | 
						|
		
 | 
						|
		if (IsMenu(m_hListMenu)) ::DestroyMenu(m_hListMenu);
 | 
						|
	}
 | 
						|
 | 
						|
	inline int CTab::AddTabPage(WndPtr pView, LPCTSTR szTabText, HICON hIcon, UINT idTab)
 | 
						|
	{
 | 
						|
		assert(pView.get());
 | 
						|
		assert(lstrlen(szTabText) < MAX_MENU_STRING);
 | 
						|
 | 
						|
		m_vTabViews.push_back(pView);
 | 
						|
 | 
						|
		TabPageInfo tpi = {0};
 | 
						|
		tpi.pView = pView.get();
 | 
						|
		tpi.idTab = idTab;
 | 
						|
		lstrcpyn(tpi.szTabText, szTabText, MAX_MENU_STRING);
 | 
						|
		if (hIcon)
 | 
						|
			tpi.iImage = ImageList_AddIcon(GetImageList(), hIcon);
 | 
						|
		else
 | 
						|
			tpi.iImage = -1;
 | 
						|
 | 
						|
		int iNewPage = (int)m_vTabPageInfo.size();
 | 
						|
		m_vTabPageInfo.push_back(tpi);
 | 
						|
 | 
						|
		if (m_hWnd)
 | 
						|
		{
 | 
						|
			TCITEM tie = {0};
 | 
						|
			tie.mask = TCIF_TEXT | TCIF_IMAGE;
 | 
						|
			tie.iImage = tpi.iImage;
 | 
						|
			tie.pszText = tpi.szTabText;
 | 
						|
			TabCtrl_InsertItem(m_hWnd, iNewPage, &tie);
 | 
						|
 | 
						|
			SetTabSize();
 | 
						|
			SelectPage(iNewPage);
 | 
						|
			NotifyChanged();
 | 
						|
		}
 | 
						|
 | 
						|
		return iNewPage;
 | 
						|
	}
 | 
						|
 | 
						|
	inline int CTab::AddTabPage(WndPtr pView, LPCTSTR szTabText, int idIcon, UINT idTab /* = 0*/)
 | 
						|
	{
 | 
						|
		HICON hIcon = (HICON)LoadImage(GetApp()->GetResourceHandle(), MAKEINTRESOURCE(idIcon), IMAGE_ICON, 0, 0, LR_SHARED);
 | 
						|
		return AddTabPage(pView, szTabText, hIcon, idTab);
 | 
						|
	}
 | 
						|
 | 
						|
	inline int CTab::AddTabPage(WndPtr pView, LPCTSTR szTabText)
 | 
						|
	{
 | 
						|
		return AddTabPage(pView, szTabText, (HICON)0, 0);
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTab::DrawCloseButton(CDC& DrawDC)
 | 
						|
	{
 | 
						|
		// The close button isn't displayed on Win95
 | 
						|
		if (GetWinVersion() == 1400)  return;
 | 
						|
 | 
						|
		if (!m_bShowButtons) return;
 | 
						|
		if (!GetActiveView()) return;
 | 
						|
		if (!(GetWindowLongPtr(GWL_STYLE) & TCS_FIXEDWIDTH)) return;
 | 
						|
		if (!(GetWindowLongPtr(GWL_STYLE) & TCS_OWNERDRAWFIXED)) return;
 | 
						|
 | 
						|
		// Determine the close button's drawing position relative to the window
 | 
						|
		CRect rcClose = GetCloseRect();
 | 
						|
 | 
						|
		CPoint pt = GetCursorPos();
 | 
						|
		ScreenToClient(pt);
 | 
						|
		UINT uState = rcClose.PtInRect(pt)? m_IsClosePressed? 2: 1: 0;
 | 
						|
 | 
						|
		// Draw the outer highlight for the close button
 | 
						|
		if (!IsRectEmpty(&rcClose))
 | 
						|
		{
 | 
						|
			switch (uState)
 | 
						|
			{
 | 
						|
			case 0:
 | 
						|
				{
 | 
						|
					DrawDC.CreatePen(PS_SOLID, 1, RGB(232, 228, 220));
 | 
						|
 | 
						|
					DrawDC.MoveTo(rcClose.left, rcClose.bottom);
 | 
						|
					DrawDC.LineTo(rcClose.right, rcClose.bottom);
 | 
						|
					DrawDC.LineTo(rcClose.right, rcClose.top);
 | 
						|
					DrawDC.LineTo(rcClose.left, rcClose.top);
 | 
						|
					DrawDC.LineTo(rcClose.left, rcClose.bottom);
 | 
						|
					break;
 | 
						|
				}
 | 
						|
 | 
						|
			case 1:
 | 
						|
				{
 | 
						|
					// Draw outline, white at top, black on bottom
 | 
						|
					DrawDC.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
 | 
						|
					DrawDC.MoveTo(rcClose.left, rcClose.bottom);
 | 
						|
					DrawDC.LineTo(rcClose.right, rcClose.bottom);
 | 
						|
					DrawDC.LineTo(rcClose.right, rcClose.top);
 | 
						|
					DrawDC.CreatePen(PS_SOLID, 1, RGB(255, 255, 255));
 | 
						|
					DrawDC.LineTo(rcClose.left, rcClose.top);
 | 
						|
					DrawDC.LineTo(rcClose.left, rcClose.bottom);
 | 
						|
				}
 | 
						|
 | 
						|
				break;
 | 
						|
			case 2:
 | 
						|
				{
 | 
						|
					// Draw outline, black on top, white on bottom
 | 
						|
					DrawDC.CreatePen(PS_SOLID, 1, RGB(255, 255, 255));
 | 
						|
					DrawDC.MoveTo(rcClose.left, rcClose.bottom);
 | 
						|
					DrawDC.LineTo(rcClose.right, rcClose.bottom);
 | 
						|
					DrawDC.LineTo(rcClose.right, rcClose.top);
 | 
						|
					DrawDC.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
 | 
						|
					DrawDC.LineTo(rcClose.left, rcClose.top);
 | 
						|
					DrawDC.LineTo(rcClose.left, rcClose.bottom);
 | 
						|
				}
 | 
						|
				break;
 | 
						|
			}
 | 
						|
 | 
						|
			// Manually draw close button
 | 
						|
			DrawDC.CreatePen(PS_SOLID, 1, RGB(64, 64, 64));
 | 
						|
 | 
						|
			DrawDC.MoveTo(rcClose.left + 3, rcClose.top +3);
 | 
						|
			DrawDC.LineTo(rcClose.right - 2, rcClose.bottom -2);
 | 
						|
 | 
						|
			DrawDC.MoveTo(rcClose.left + 4, rcClose.top +3);
 | 
						|
			DrawDC.LineTo(rcClose.right - 2, rcClose.bottom -3);
 | 
						|
 | 
						|
			DrawDC.MoveTo(rcClose.left + 3, rcClose.top +4);
 | 
						|
			DrawDC.LineTo(rcClose.right - 3, rcClose.bottom -2);
 | 
						|
 | 
						|
			DrawDC.MoveTo(rcClose.right -3, rcClose.top +3);
 | 
						|
			DrawDC.LineTo(rcClose.left + 2, rcClose.bottom -2);
 | 
						|
 | 
						|
			DrawDC.MoveTo(rcClose.right -3, rcClose.top +4);
 | 
						|
			DrawDC.LineTo(rcClose.left + 3, rcClose.bottom -2);
 | 
						|
 | 
						|
			DrawDC.MoveTo(rcClose.right -4, rcClose.top +3);
 | 
						|
			DrawDC.LineTo(rcClose.left + 2, rcClose.bottom -3);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTab::DrawListButton(CDC& DrawDC)
 | 
						|
	{
 | 
						|
		// The list button isn't displayed on Win95
 | 
						|
		if (GetWinVersion() == 1400)  return;
 | 
						|
 | 
						|
		if (!m_bShowButtons) return;
 | 
						|
		if (!GetActiveView()) return;
 | 
						|
		if (!(GetWindowLongPtr(GWL_STYLE) & TCS_FIXEDWIDTH)) return;
 | 
						|
		if (!(GetWindowLongPtr(GWL_STYLE) & TCS_OWNERDRAWFIXED)) return;
 | 
						|
 | 
						|
		// Determine the list button's drawing position relative to the window
 | 
						|
		CRect rcList = GetListRect();
 | 
						|
 | 
						|
		CPoint pt = GetCursorPos();
 | 
						|
		ScreenToClient(pt);
 | 
						|
		UINT uState = rcList.PtInRect(pt)? 1: 0;
 | 
						|
		if (m_IsListMenuActive) uState = 2;
 | 
						|
 | 
						|
		// Draw the outer highlight for the list button
 | 
						|
		if (!IsRectEmpty(&rcList))
 | 
						|
		{
 | 
						|
			switch (uState)
 | 
						|
			{
 | 
						|
			case 0:
 | 
						|
				{
 | 
						|
					DrawDC.CreatePen(PS_SOLID, 1, RGB(232, 228, 220));
 | 
						|
 | 
						|
					DrawDC.MoveTo(rcList.left, rcList.bottom);
 | 
						|
					DrawDC.LineTo(rcList.right, rcList.bottom);
 | 
						|
					DrawDC.LineTo(rcList.right, rcList.top);
 | 
						|
					DrawDC.LineTo(rcList.left, rcList.top);
 | 
						|
					DrawDC.LineTo(rcList.left, rcList.bottom);
 | 
						|
					break;
 | 
						|
				}
 | 
						|
 | 
						|
			case 1:
 | 
						|
				{
 | 
						|
					// Draw outline, white at top, black on bottom
 | 
						|
					DrawDC.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
 | 
						|
					DrawDC.MoveTo(rcList.left, rcList.bottom);
 | 
						|
					DrawDC.LineTo(rcList.right, rcList.bottom);
 | 
						|
					DrawDC.LineTo(rcList.right, rcList.top);
 | 
						|
					DrawDC.CreatePen(PS_SOLID, 1, RGB(255, 255, 255));
 | 
						|
					DrawDC.LineTo(rcList.left, rcList.top);
 | 
						|
					DrawDC.LineTo(rcList.left, rcList.bottom);
 | 
						|
				}
 | 
						|
 | 
						|
				break;
 | 
						|
			case 2:
 | 
						|
				{
 | 
						|
					// Draw outline, black on top, white on bottom
 | 
						|
					DrawDC.CreatePen(PS_SOLID, 1, RGB(255, 255, 255));
 | 
						|
					DrawDC.MoveTo(rcList.left, rcList.bottom);
 | 
						|
					DrawDC.LineTo(rcList.right, rcList.bottom);
 | 
						|
					DrawDC.LineTo(rcList.right, rcList.top);
 | 
						|
					DrawDC.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
 | 
						|
					DrawDC.LineTo(rcList.left, rcList.top);
 | 
						|
					DrawDC.LineTo(rcList.left, rcList.bottom);
 | 
						|
				}
 | 
						|
				break;
 | 
						|
			}
 | 
						|
 | 
						|
			// Manually draw list button
 | 
						|
			DrawDC.CreatePen(PS_SOLID, 1, RGB(64, 64, 64));
 | 
						|
 | 
						|
			int MaxLength = (int)(0.65 * rcList.Width());
 | 
						|
			int topGap = 1 + rcList.Height()/3;
 | 
						|
			for (int i = 0; i <= MaxLength/2; i++)
 | 
						|
			{
 | 
						|
				int Length = MaxLength - 2*i;
 | 
						|
				DrawDC.MoveTo(rcList.left +1 + (rcList.Width() - Length)/2, rcList.top +topGap +i);
 | 
						|
				DrawDC.LineTo(rcList.left +1 + (rcList.Width() - Length)/2 + Length, rcList.top +topGap +i);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTab::DrawTabs(CDC& dcMem)
 | 
						|
	{
 | 
						|
		// Draw the tab buttons:
 | 
						|
		for (int i = 0; i < TabCtrl_GetItemCount(m_hWnd); ++i)
 | 
						|
		{
 | 
						|
			CRect rcItem;
 | 
						|
			TabCtrl_GetItemRect(m_hWnd, i, &rcItem);
 | 
						|
			if (!rcItem.IsRectEmpty())
 | 
						|
			{
 | 
						|
				if (i == TabCtrl_GetCurSel(m_hWnd))
 | 
						|
				{
 | 
						|
					dcMem.CreateSolidBrush(RGB(248,248,248));
 | 
						|
					dcMem.SetBkColor(RGB(248,248,248));
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					dcMem.CreateSolidBrush(RGB(200,200,200));
 | 
						|
					dcMem.SetBkColor(RGB(200,200,200));
 | 
						|
				}
 | 
						|
 | 
						|
				dcMem.CreatePen(PS_SOLID, 1, RGB(160, 160, 160));
 | 
						|
				dcMem.RoundRect(rcItem.left+1, rcItem.top, rcItem.right+2, rcItem.bottom, 6, 6);
 | 
						|
 | 
						|
				if (rcItem.Width() >= 24)
 | 
						|
				{
 | 
						|
					TCHAR szText[30];
 | 
						|
					TCITEM tcItem = {0};
 | 
						|
					tcItem.mask = TCIF_TEXT | TCIF_IMAGE;
 | 
						|
					tcItem.cchTextMax = 30;
 | 
						|
					tcItem.pszText = szText;
 | 
						|
					TabCtrl_GetItem(m_hWnd, i, &tcItem);
 | 
						|
					int xImage;
 | 
						|
					int yImage;
 | 
						|
					int yOffset = 0;
 | 
						|
					if (ImageList_GetIconSize(m_himlTab, &xImage, &yImage))
 | 
						|
						yOffset = (rcItem.Height() - yImage)/2;
 | 
						|
 | 
						|
					// Draw the icon
 | 
						|
					ImageList_Draw(m_himlTab, tcItem.iImage, dcMem, rcItem.left+5, rcItem.top+yOffset, ILD_NORMAL);
 | 
						|
 | 
						|
					// Draw the text
 | 
						|
					dcMem.SelectObject(&m_Font);
 | 
						|
 | 
						|
					// Calculate the size of the text
 | 
						|
					CRect rcText = rcItem;
 | 
						|
 | 
						|
					int iImageSize = 20;
 | 
						|
					int iPadding = 4;
 | 
						|
					if (tcItem.iImage >= 0)
 | 
						|
						rcText.left += iImageSize;
 | 
						|
 | 
						|
					rcText.left += iPadding;
 | 
						|
					dcMem.DrawText(szText, -1, rcText, DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_END_ELLIPSIS);
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTab::DrawTabBorders(CDC& dcMem, CRect& rcTab)
 | 
						|
	{
 | 
						|
		BOOL IsBottomTab = (BOOL)GetWindowLongPtr(GWL_STYLE) & TCS_BOTTOM;
 | 
						|
 | 
						|
		// Draw a lighter rectangle touching the tab buttons
 | 
						|
		CRect rcItem;
 | 
						|
		TabCtrl_GetItemRect(m_hWnd, 0, &rcItem);
 | 
						|
		int left = rcItem.left +1;
 | 
						|
		int right = rcTab.right;
 | 
						|
		int top = rcTab.bottom;
 | 
						|
		int bottom = top + 3;
 | 
						|
 | 
						|
		if (!IsBottomTab)
 | 
						|
		{
 | 
						|
			bottom = MAX(rcTab.top, m_nTabHeight +4);
 | 
						|
			top = bottom -3;
 | 
						|
		}
 | 
						|
 | 
						|
		dcMem.CreateSolidBrush(RGB(248,248,248));
 | 
						|
		dcMem.CreatePen(PS_SOLID, 1, RGB(248,248,248));
 | 
						|
		if (!rcItem.IsRectEmpty())
 | 
						|
		{
 | 
						|
			dcMem.Rectangle(left, top, right, bottom);
 | 
						|
 | 
						|
			// Draw a darker line below the rectangle
 | 
						|
			dcMem.CreatePen(PS_SOLID, 1, RGB(160, 160, 160));
 | 
						|
			if (IsBottomTab)
 | 
						|
			{
 | 
						|
				dcMem.MoveTo(left-1, bottom);
 | 
						|
				dcMem.LineTo(right, bottom);
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				dcMem.MoveTo(left-1, top-1);
 | 
						|
				dcMem.LineTo(right, top-1);
 | 
						|
			}
 | 
						|
 | 
						|
			// Draw a lighter line over the darker line for the selected tab
 | 
						|
			dcMem.CreatePen(PS_SOLID, 1, RGB(248,248,248));
 | 
						|
			TabCtrl_GetItemRect(m_hWnd, TabCtrl_GetCurSel(m_hWnd), &rcItem);
 | 
						|
			OffsetRect(&rcItem, 1, 1);
 | 
						|
 | 
						|
			if (IsBottomTab)
 | 
						|
			{
 | 
						|
				dcMem.MoveTo(rcItem.left, bottom);
 | 
						|
				dcMem.LineTo(rcItem.right, bottom);
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				dcMem.MoveTo(rcItem.left, top-1);
 | 
						|
				dcMem.LineTo(rcItem.right, top-1);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	inline CRect CTab::GetCloseRect() const
 | 
						|
	{
 | 
						|
		CRect rcClose;
 | 
						|
		if (GetShowButtons())
 | 
						|
		{
 | 
						|
			rcClose= GetClientRect();
 | 
						|
			int Gap = 2;
 | 
						|
			int cx = GetSystemMetrics(SM_CXSMICON) -1;
 | 
						|
			int cy = GetSystemMetrics(SM_CYSMICON) -1;
 | 
						|
			rcClose.right -= Gap;
 | 
						|
			rcClose.left = rcClose.right - cx;
 | 
						|
 | 
						|
			if (GetTabsAtTop())
 | 
						|
				rcClose.top = Gap;
 | 
						|
			else
 | 
						|
				rcClose.top = MAX(Gap, rcClose.bottom - m_nTabHeight);
 | 
						|
 | 
						|
			rcClose.bottom = rcClose.top + cy;
 | 
						|
		}
 | 
						|
		return rcClose;
 | 
						|
	}
 | 
						|
 | 
						|
	inline HMENU CTab::GetListMenu()
 | 
						|
	{
 | 
						|
		if (IsMenu(m_hListMenu))
 | 
						|
			::DestroyMenu(m_hListMenu);
 | 
						|
		
 | 
						|
		m_hListMenu = CreatePopupMenu();
 | 
						|
 | 
						|
		// Add the menu items
 | 
						|
		for(UINT u = 0; u < MIN(GetAllTabs().size(), 9); ++u)
 | 
						|
		{
 | 
						|
			TCHAR szMenuString[MAX_MENU_STRING+1];
 | 
						|
			TCHAR szTabText[MAX_MENU_STRING];
 | 
						|
			lstrcpyn(szTabText, GetAllTabs()[u].szTabText, MAX_MENU_STRING -4);
 | 
						|
			wsprintf(szMenuString, _T("&%d %s"), u+1, szTabText);
 | 
						|
			AppendMenu(m_hListMenu, MF_STRING, IDW_FIRSTCHILD +u, szMenuString);
 | 
						|
		}
 | 
						|
		if (GetAllTabs().size() >= 10)
 | 
						|
			AppendMenu(m_hListMenu, MF_STRING, IDW_FIRSTCHILD +9, _T("More Windows"));
 | 
						|
 | 
						|
		// Add a checkmark to the menu
 | 
						|
		int iSelected = GetCurSel();
 | 
						|
		if (iSelected < 9)
 | 
						|
			CheckMenuItem(m_hListMenu, iSelected, MF_BYPOSITION|MF_CHECKED);
 | 
						|
 | 
						|
		return m_hListMenu;
 | 
						|
	}
 | 
						|
 | 
						|
	inline CRect CTab::GetListRect() const
 | 
						|
	{
 | 
						|
		CRect rcList;
 | 
						|
		if (GetShowButtons())
 | 
						|
		{
 | 
						|
			CRect rcClose = GetCloseRect();
 | 
						|
			rcList = rcClose;
 | 
						|
			rcList.OffsetRect( -(rcClose.Width() + 2), 0);
 | 
						|
			rcList.InflateRect(-1, 0);
 | 
						|
		}
 | 
						|
		return rcList;
 | 
						|
	}
 | 
						|
 | 
						|
	inline SIZE CTab::GetMaxTabSize() const
 | 
						|
	{
 | 
						|
		CSize Size;
 | 
						|
 | 
						|
		for (int i = 0; i < TabCtrl_GetItemCount(m_hWnd); i++)
 | 
						|
		{
 | 
						|
			CClientDC dcClient(this);
 | 
						|
			dcClient.SelectObject(&m_Font);
 | 
						|
			std::vector<TCHAR> vTitle(MAX_MENU_STRING, _T('\0'));
 | 
						|
			TCHAR* pszTitle = &vTitle.front();
 | 
						|
			TCITEM tcItem = {0};
 | 
						|
			tcItem.mask = TCIF_TEXT |TCIF_IMAGE;
 | 
						|
			tcItem.cchTextMax = MAX_MENU_STRING;
 | 
						|
			tcItem.pszText = pszTitle;
 | 
						|
			TabCtrl_GetItem(m_hWnd, i, &tcItem);
 | 
						|
			CSize TempSize = dcClient.GetTextExtentPoint32(pszTitle, lstrlen(pszTitle));
 | 
						|
 | 
						|
			int iImageSize = 0;
 | 
						|
			int iPadding = 6;
 | 
						|
			if (tcItem.iImage >= 0)
 | 
						|
				iImageSize = 20;
 | 
						|
			TempSize.cx += iImageSize + iPadding;
 | 
						|
 | 
						|
			if (TempSize.cx > Size.cx)
 | 
						|
				Size = TempSize;
 | 
						|
		}
 | 
						|
 | 
						|
		return Size;
 | 
						|
	}
 | 
						|
 | 
						|
	inline BOOL CTab::GetTabsAtTop() const
 | 
						|
	// Returns TRUE if the contol's tabs are placed at the top
 | 
						|
	{
 | 
						|
		DWORD dwStyle = (DWORD)GetWindowLongPtr(GWL_STYLE);
 | 
						|
		return (!(dwStyle & TCS_BOTTOM));
 | 
						|
	}
 | 
						|
 | 
						|
	inline int CTab::GetTextHeight() const
 | 
						|
	{
 | 
						|
		CClientDC dcClient(this);
 | 
						|
		dcClient.SelectObject(&m_Font);
 | 
						|
		CSize szText = dcClient.GetTextExtentPoint32(_T("Text"), lstrlen(_T("Text")));
 | 
						|
		return szText.cy;
 | 
						|
	}
 | 
						|
 | 
						|
	inline int CTab::GetTabIndex(CWnd* pWnd) const
 | 
						|
	{
 | 
						|
		assert(pWnd);
 | 
						|
 | 
						|
		for (int i = 0; i < (int)m_vTabPageInfo.size(); ++i)
 | 
						|
		{
 | 
						|
			if (m_vTabPageInfo[i].pView == pWnd)
 | 
						|
				return i;
 | 
						|
		}
 | 
						|
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	inline TabPageInfo CTab::GetTabPageInfo(UINT nTab) const
 | 
						|
	{
 | 
						|
		assert (nTab < m_vTabPageInfo.size());
 | 
						|
 | 
						|
		return m_vTabPageInfo[nTab];
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTab::NotifyChanged()
 | 
						|
	{
 | 
						|
		NMHDR nmhdr = {0};
 | 
						|
		nmhdr.hwndFrom = m_hWnd;
 | 
						|
		nmhdr.code = UWM_TAB_CHANGED;
 | 
						|
		GetParent()->SendMessage(WM_NOTIFY, 0L, (LPARAM)&nmhdr);
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTab::OnCreate()
 | 
						|
	{
 | 
						|
		SetFont(&m_Font, TRUE);
 | 
						|
		
 | 
						|
		// Assign ImageList unless we are owner drawn
 | 
						|
		if (!(GetWindowLongPtr(GWL_STYLE) & TCS_OWNERDRAWFIXED))
 | 
						|
			TabCtrl_SetImageList(m_hWnd, m_himlTab);
 | 
						|
 | 
						|
		for (int i = 0; i < (int)m_vTabPageInfo.size(); ++i)
 | 
						|
		{
 | 
						|
			// Add tabs for each view.
 | 
						|
			TCITEM tie = {0};
 | 
						|
			tie.mask = TCIF_TEXT | TCIF_IMAGE;
 | 
						|
			tie.iImage = m_vTabPageInfo[i].iImage;
 | 
						|
			tie.pszText = m_vTabPageInfo[i].szTabText;
 | 
						|
			TabCtrl_InsertItem(m_hWnd, i, &tie);
 | 
						|
		}
 | 
						|
 | 
						|
		int HeightGap = 5;
 | 
						|
		SetTabHeight(MAX(20, (GetTextHeight() + HeightGap)));
 | 
						|
		SelectPage(0);
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTab::OnLButtonDown(WPARAM /*wParam*/, LPARAM lParam)
 | 
						|
	{
 | 
						|
		CPoint pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
 | 
						|
 | 
						|
		if (GetCloseRect().PtInRect(pt))
 | 
						|
		{
 | 
						|
			m_IsClosePressed = TRUE;
 | 
						|
			SetCapture();
 | 
						|
			CClientDC dc(this);
 | 
						|
			DrawCloseButton(dc);
 | 
						|
		}
 | 
						|
		else
 | 
						|
			m_IsClosePressed = FALSE;
 | 
						|
 | 
						|
		if (GetListRect().PtInRect(pt))
 | 
						|
		{
 | 
						|
			ShowListMenu();
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTab::OnLButtonUp(WPARAM /*wParam*/, LPARAM lParam)
 | 
						|
	{
 | 
						|
		ReleaseCapture();
 | 
						|
		CPoint pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
 | 
						|
		if (m_IsClosePressed && GetCloseRect().PtInRect(pt))
 | 
						|
		{
 | 
						|
			RemoveTabPage(GetCurSel());
 | 
						|
			if (GetActiveView())
 | 
						|
				GetActiveView()->RedrawWindow();
 | 
						|
		}
 | 
						|
 | 
						|
		m_IsClosePressed = FALSE;
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTab::OnMouseLeave(WPARAM /*wParam*/, LPARAM /*lParam*/)
 | 
						|
	{
 | 
						|
		CClientDC dc(this);
 | 
						|
		DrawCloseButton(dc);
 | 
						|
		DrawListButton(dc);
 | 
						|
 | 
						|
		m_IsTracking = FALSE;
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTab::OnMouseMove(WPARAM /*wParam*/, LPARAM /*lParam*/)
 | 
						|
	{
 | 
						|
		if (!m_IsListMenuActive && m_IsListPressed)
 | 
						|
		{
 | 
						|
			m_IsListPressed = FALSE;
 | 
						|
		}
 | 
						|
 | 
						|
		if (!m_IsTracking)
 | 
						|
		{
 | 
						|
			TRACKMOUSEEVENT TrackMouseEventStruct = {0};
 | 
						|
			TrackMouseEventStruct.cbSize = sizeof(TrackMouseEventStruct);
 | 
						|
			TrackMouseEventStruct.dwFlags = TME_LEAVE;
 | 
						|
			TrackMouseEventStruct.hwndTrack = m_hWnd;
 | 
						|
			_TrackMouseEvent(&TrackMouseEventStruct);
 | 
						|
			m_IsTracking = TRUE;
 | 
						|
		}
 | 
						|
 | 
						|
		CClientDC dc(this);
 | 
						|
		DrawCloseButton(dc);
 | 
						|
		DrawListButton(dc);
 | 
						|
	}
 | 
						|
 | 
						|
	inline LRESULT CTab::OnNCHitTest(WPARAM wParam, LPARAM lParam)
 | 
						|
	{
 | 
						|
		// Ensure we have an arrow cursor when the tab has no view window
 | 
						|
		if (0 == GetAllTabs().size())
 | 
						|
			SetCursor(LoadCursor(NULL, IDC_ARROW));
 | 
						|
 | 
						|
		// Cause WM_LBUTTONUP and WM_LBUTTONDOWN messages to be sent for buttons
 | 
						|
		CPoint pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
 | 
						|
		ScreenToClient(pt);
 | 
						|
		if (GetCloseRect().PtInRect(pt)) return HTCLIENT;
 | 
						|
		if (GetListRect().PtInRect(pt))  return HTCLIENT;
 | 
						|
 | 
						|
		return CWnd::WndProcDefault(WM_NCHITTEST, wParam, lParam);
 | 
						|
	}
 | 
						|
 | 
						|
	inline LRESULT CTab::OnNotifyReflect(WPARAM wParam, LPARAM lParam)
 | 
						|
	{
 | 
						|
		UNREFERENCED_PARAMETER(wParam);
 | 
						|
 | 
						|
		switch (((LPNMHDR)lParam)->code)
 | 
						|
		{
 | 
						|
		case TCN_SELCHANGE:
 | 
						|
			{
 | 
						|
				// Display the newly selected tab page
 | 
						|
				int nPage = GetCurSel();
 | 
						|
				ShowActiveView(m_vTabPageInfo[nPage].pView);
 | 
						|
			}
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		return 0L;
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTab::Paint()
 | 
						|
	{
 | 
						|
		// Microsoft's drawing for a tab control is rubbish, so we do our own.
 | 
						|
		// We use double buffering and regions to eliminate flicker
 | 
						|
 | 
						|
		// Create the memory DC and bitmap
 | 
						|
		CClientDC dcView(this);
 | 
						|
		CMemDC dcMem(&dcView);
 | 
						|
		CRect rcClient = GetClientRect();
 | 
						|
		dcMem.CreateCompatibleBitmap(&dcView, rcClient.Width(), rcClient.Height());
 | 
						|
 | 
						|
		if (0 == GetItemCount())
 | 
						|
		{
 | 
						|
			// No tabs, so simply display a grey background and exit
 | 
						|
			COLORREF rgbDialog = GetSysColor(COLOR_BTNFACE);
 | 
						|
			dcView.SolidFill(rgbDialog, rcClient);
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		// Create a clipping region. Its the overall tab window's region,
 | 
						|
		//  less the region belonging to the individual tab view's client area
 | 
						|
		CRgn rgnSrc1 = ::CreateRectRgn(rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
 | 
						|
		CRect rcTab = GetClientRect();
 | 
						|
		TabCtrl_AdjustRect(m_hWnd, FALSE, &rcTab);
 | 
						|
		if (rcTab.Height() < 0)
 | 
						|
			rcTab.top = rcTab.bottom;
 | 
						|
		if (rcTab.Width() < 0)
 | 
						|
			rcTab.left = rcTab.right;
 | 
						|
 | 
						|
		CRgn rgnSrc2 = ::CreateRectRgn(rcTab.left, rcTab.top, rcTab.right, rcTab.bottom);
 | 
						|
		CRgn rgnClip = ::CreateRectRgn(0, 0, 0, 0);
 | 
						|
		::CombineRgn(rgnClip, rgnSrc1, rgnSrc2, RGN_DIFF);
 | 
						|
 | 
						|
		// Use the region in the memory DC to paint the grey background
 | 
						|
		dcMem.SelectClipRgn(&rgnClip);
 | 
						|
		HWND hWndParent = ::GetParent(m_hWnd);
 | 
						|
		CDC dcParent = ::GetDC(hWndParent);
 | 
						|
		HBRUSH hBrush = (HBRUSH) SendMessage(hWndParent, WM_CTLCOLORDLG, (WPARAM)dcParent.GetHDC(), (LPARAM)hWndParent);
 | 
						|
		dcMem.SelectObject(FromHandle(hBrush));
 | 
						|
		dcMem.PaintRgn(&rgnClip);
 | 
						|
 | 
						|
		// Draw the tab buttons on the memory DC:
 | 
						|
		DrawTabs(dcMem);
 | 
						|
 | 
						|
		// Draw buttons and tab borders
 | 
						|
		DrawCloseButton(dcMem);
 | 
						|
		DrawListButton(dcMem);
 | 
						|
		DrawTabBorders(dcMem, rcTab);
 | 
						|
 | 
						|
		// Now copy our from our memory DC to the window DC
 | 
						|
		dcView.SelectClipRgn(&rgnClip);
 | 
						|
		dcView.BitBlt(0, 0, rcClient.Width(), rcClient.Height(), &dcMem, 0, 0, SRCCOPY);
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTab::PreCreate(CREATESTRUCT &cs)
 | 
						|
	{
 | 
						|
		// For Tabs on the bottom, add the TCS_BOTTOM style
 | 
						|
		cs.style = WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE;
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTab::PreRegisterClass(WNDCLASS &wc)
 | 
						|
	{
 | 
						|
		wc.lpszClassName = WC_TABCONTROL;
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTab::RecalcLayout()
 | 
						|
	{
 | 
						|
		if (IsWindow())
 | 
						|
		{
 | 
						|
			if (GetActiveView())
 | 
						|
			{
 | 
						|
				// Set the tab sizes
 | 
						|
				SetTabSize();
 | 
						|
 | 
						|
				// Position the View over the tab control's display area
 | 
						|
				CRect rc = GetClientRect();
 | 
						|
				TabCtrl_AdjustRect(m_hWnd, FALSE, &rc);
 | 
						|
				GetActiveView()->SetWindowPos(NULL, rc, SWP_SHOWWINDOW);
 | 
						|
			}
 | 
						|
			else
 | 
						|
				RedrawWindow();
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTab::RemoveTabPage(int nPage)
 | 
						|
	{
 | 
						|
		if ((nPage < 0) || (nPage > (int)m_vTabPageInfo.size() -1))
 | 
						|
			return;
 | 
						|
 | 
						|
		// Remove the tab
 | 
						|
		TabCtrl_DeleteItem(m_hWnd, nPage);
 | 
						|
 | 
						|
		// Remove the TapPageInfo entry
 | 
						|
		std::vector<TabPageInfo>::iterator itTPI = m_vTabPageInfo.begin() + nPage;
 | 
						|
		CWnd* pView = (*itTPI).pView;
 | 
						|
		int iImage = (*itTPI).iImage;
 | 
						|
		if (iImage >= 0)
 | 
						|
			TabCtrl_RemoveImage(m_hWnd, iImage);
 | 
						|
 | 
						|
		if (pView == m_pActiveView)
 | 
						|
			m_pActiveView = 0;
 | 
						|
 | 
						|
		(*itTPI).pView->Destroy();
 | 
						|
		m_vTabPageInfo.erase(itTPI);
 | 
						|
 | 
						|
		std::vector<WndPtr>::iterator itView;
 | 
						|
		for (itView = m_vTabViews.begin(); itView < m_vTabViews.end(); ++itView)
 | 
						|
		{
 | 
						|
			if ((*itView).get() == pView)
 | 
						|
			{
 | 
						|
				m_vTabViews.erase(itView);
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if (IsWindow())
 | 
						|
		{
 | 
						|
			if (m_vTabPageInfo.size() > 0)
 | 
						|
			{
 | 
						|
				SetTabSize();
 | 
						|
				SelectPage(0);
 | 
						|
			}
 | 
						|
			else
 | 
						|
				ShowActiveView(NULL);
 | 
						|
 | 
						|
			NotifyChanged();
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTab::SelectPage(int nPage)
 | 
						|
	{
 | 
						|
		if ((nPage >= 0) && (nPage < GetItemCount()))
 | 
						|
		{
 | 
						|
			if (nPage != GetCurSel())
 | 
						|
				SetCurSel(nPage);
 | 
						|
			
 | 
						|
			ShowActiveView(m_vTabPageInfo[nPage].pView);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTab::SetFixedWidth(BOOL bEnabled)
 | 
						|
	{
 | 
						|
		DWORD dwStyle = (DWORD)GetWindowLongPtr(GWL_STYLE);
 | 
						|
		if (bEnabled)
 | 
						|
			SetWindowLongPtr(GWL_STYLE, dwStyle | TCS_FIXEDWIDTH);
 | 
						|
		else
 | 
						|
			SetWindowLongPtr(GWL_STYLE, dwStyle & ~TCS_FIXEDWIDTH);
 | 
						|
 | 
						|
		RecalcLayout();
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTab::SetOwnerDraw(BOOL bEnabled)
 | 
						|
	// Enable or disable owner draw
 | 
						|
	{
 | 
						|
		DWORD dwStyle = (DWORD)GetWindowLongPtr(GWL_STYLE);
 | 
						|
		if (bEnabled)
 | 
						|
		{
 | 
						|
			SetWindowLongPtr(GWL_STYLE, dwStyle | TCS_OWNERDRAWFIXED);
 | 
						|
			TabCtrl_SetImageList(m_hWnd, NULL);
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			SetWindowLongPtr(GWL_STYLE, dwStyle & ~TCS_OWNERDRAWFIXED);
 | 
						|
			TabCtrl_SetImageList(m_hWnd, m_himlTab);
 | 
						|
		}
 | 
						|
 | 
						|
		RecalcLayout();
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTab::SetShowButtons(BOOL bShow)
 | 
						|
	{
 | 
						|
		m_bShowButtons = bShow;
 | 
						|
		RecalcLayout();
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTab::SetTabIcon(int i, HICON hIcon)
 | 
						|
	// Changes or sets the tab's icon
 | 
						|
	{
 | 
						|
		assert (GetItemCount() > i);
 | 
						|
		TCITEM tci = {0};
 | 
						|
		tci.mask = TCIF_IMAGE;
 | 
						|
		GetItem(i, &tci);
 | 
						|
		if (tci.iImage >= 0)
 | 
						|
		{
 | 
						|
			ImageList_ReplaceIcon(GetImageList(), i, hIcon);
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			int iImage = ImageList_AddIcon(GetImageList(), hIcon);
 | 
						|
			tci.iImage = iImage;
 | 
						|
			TabCtrl_SetItem(m_hWnd, i, &tci);
 | 
						|
			m_vTabPageInfo[i].iImage = iImage;
 | 
						|
		}
 | 
						|
	}	
 | 
						|
 | 
						|
	inline void CTab::SetTabsAtTop(BOOL bTop)
 | 
						|
	// Positions the tabs at the top or botttom of the control
 | 
						|
	{
 | 
						|
		DWORD dwStyle = (DWORD)GetWindowLongPtr(GWL_STYLE);
 | 
						|
 | 
						|
		if (bTop)
 | 
						|
			dwStyle &= ~TCS_BOTTOM;
 | 
						|
		else
 | 
						|
			dwStyle |= TCS_BOTTOM;
 | 
						|
 | 
						|
		SetWindowLongPtr(GWL_STYLE, dwStyle);
 | 
						|
		RecalcLayout();
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTab::SetTabSize()
 | 
						|
	{
 | 
						|
		if (GetItemCount() > 0)
 | 
						|
		{
 | 
						|
			CRect rc = GetClientRect();
 | 
						|
			TabCtrl_AdjustRect(m_hWnd, FALSE, &rc);
 | 
						|
 | 
						|
			int xGap = 2;
 | 
						|
			if (m_bShowButtons) xGap += GetCloseRect().Width() + GetListRect().Width() +2;
 | 
						|
 | 
						|
			int nItemWidth = MIN( GetMaxTabSize().cx, (rc.Width() - xGap)/GetItemCount() );
 | 
						|
			nItemWidth = MAX(nItemWidth, 0);
 | 
						|
			SendMessage(TCM_SETITEMSIZE, 0L, MAKELPARAM(nItemWidth, m_nTabHeight));
 | 
						|
			NotifyChanged();
 | 
						|
		} 
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTab::SetTabText(UINT nTab, LPCTSTR szText)
 | 
						|
	{
 | 
						|
		// Allows the text to be changed on an existing tab
 | 
						|
		if (nTab < GetAllTabs().size())
 | 
						|
		{
 | 
						|
			TCITEM Item = {0};
 | 
						|
			std::vector<TCHAR> vTChar(MAX_MENU_STRING+1, _T('\0'));
 | 
						|
			TCHAR* pTChar = &vTChar.front();
 | 
						|
			lstrcpyn(pTChar, szText, MAX_MENU_STRING);
 | 
						|
			Item.mask = TCIF_TEXT;
 | 
						|
			Item.pszText = pTChar;
 | 
						|
 | 
						|
			if (TabCtrl_SetItem(m_hWnd, nTab, &Item))
 | 
						|
				lstrcpyn(m_vTabPageInfo[nTab].szTabText, pTChar, MAX_MENU_STRING);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTab::ShowActiveView(CWnd* pView)
 | 
						|
	// Sets or changes the View window displayed within the tab page
 | 
						|
	{
 | 
						|
		// Hide the old view
 | 
						|
		if (GetActiveView() && (GetActiveView()->IsWindow()))
 | 
						|
			GetActiveView()->ShowWindow(SW_HIDE);
 | 
						|
 | 
						|
		// Assign the view window
 | 
						|
		m_pActiveView = pView;
 | 
						|
 | 
						|
		if (m_pActiveView && m_hWnd)
 | 
						|
		{
 | 
						|
			if (!m_pActiveView->IsWindow())
 | 
						|
			{
 | 
						|
				// The tab control is already created, so create the new view too
 | 
						|
				GetActiveView()->Create(this);
 | 
						|
			}
 | 
						|
	
 | 
						|
			// Position the View over the tab control's display area
 | 
						|
			CRect rc = GetClientRect();
 | 
						|
			TabCtrl_AdjustRect(m_hWnd, FALSE, &rc);
 | 
						|
			GetActiveView()->SetWindowPos(HWND_TOP, rc, SWP_SHOWWINDOW);
 | 
						|
			GetActiveView()->SetFocus();
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTab::ShowListMenu()
 | 
						|
	// Displays the list of windows in a popup menu
 | 
						|
	{
 | 
						|
		if (!m_IsListPressed)
 | 
						|
		{
 | 
						|
			m_IsListPressed = TRUE;
 | 
						|
			HMENU hMenu = GetListMenu();
 | 
						|
	
 | 
						|
			CPoint pt(GetListRect().left, GetListRect().top + GetTabHeight());
 | 
						|
			ClientToScreen(pt);
 | 
						|
 | 
						|
			// Choosing the frame's hwnd for the menu's messages will automatically theme the popup menu
 | 
						|
			HWND MenuHwnd = GetAncestor()->GetHwnd();
 | 
						|
			int nPage = 0;
 | 
						|
			m_IsListMenuActive = TRUE;
 | 
						|
			nPage = TrackPopupMenuEx(hMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD, pt.x, pt.y, MenuHwnd, NULL) - IDW_FIRSTCHILD;
 | 
						|
			if ((nPage >= 0) && (nPage < 9)) SelectPage(nPage);
 | 
						|
			if (nPage == 9) ShowListDialog();
 | 
						|
			m_IsListMenuActive = FALSE;
 | 
						|
		}
 | 
						|
 | 
						|
		CClientDC dc(this);
 | 
						|
		DrawListButton(dc);
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTab::ShowListDialog()
 | 
						|
	{
 | 
						|
		// Definition of a dialog template which displays a List Box
 | 
						|
		unsigned char dlg_Template[] =
 | 
						|
		{
 | 
						|
			0x01,0x00,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0xc8,0x00,0xc8,0x90,0x03,
 | 
						|
			0x00,0x00,0x00,0x00,0x00,0xdc,0x00,0x8e,0x00,0x00,0x00,0x00,0x00,0x53,0x00,0x65,
 | 
						|
			0x00,0x6c,0x00,0x65,0x00,0x63,0x00,0x74,0x00,0x20,0x00,0x57,0x00,0x69,0x00,0x6e,
 | 
						|
			0x00,0x64,0x00,0x6f,0x00,0x77,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x01,0x4d,
 | 
						|
			0x00,0x53,0x00,0x20,0x00,0x53,0x00,0x68,0x00,0x65,0x00,0x6c,0x00,0x6c,0x00,0x20,
 | 
						|
			0x00,0x44,0x00,0x6c,0x00,0x67,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 | 
						|
			0x00,0x00,0x00,0x01,0x00,0x01,0x50,0x40,0x00,0x7a,0x00,0x25,0x00,0x0f,0x00,0x01,
 | 
						|
			0x00,0x00,0x00,0xff,0xff,0x80,0x00,0x4f,0x00,0x4b,0x00,0x00,0x00,0x00,0x00,0x00,
 | 
						|
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x50,0x7a,0x00,0x7a,0x00,0x25,
 | 
						|
			0x00,0x0f,0x00,0x02,0x00,0x00,0x00,0xff,0xff,0x80,0x00,0x43,0x00,0x61,0x00,0x6e,
 | 
						|
			0x00,0x63,0x00,0x65,0x00,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 | 
						|
			0x00,0x02,0x00,0x01,0x01,0x21,0x50,0x06,0x00,0x06,0x00,0xcf,0x00,0x6d,0x00,0x79,
 | 
						|
			0x00,0x00,0x00,0xff,0xff,0x83,0x00,0x00,0x00,0x00,0x00
 | 
						|
		};
 | 
						|
 | 
						|
		// Display the modal dialog. The dialog is defined in the dialog template rather
 | 
						|
		// than in the resource script (rc) file.
 | 
						|
		CSelectDialog MyDialog((LPCDLGTEMPLATE) dlg_Template);
 | 
						|
		for(UINT u = 0; u < GetAllTabs().size(); ++u)
 | 
						|
		{
 | 
						|
			MyDialog.AddItem(GetAllTabs()[u].szTabText);
 | 
						|
		}
 | 
						|
 | 
						|
		int iSelected = (int)MyDialog.DoModal();
 | 
						|
		if (iSelected >= 0) SelectPage(iSelected);
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTab::SwapTabs(UINT nTab1, UINT nTab2)
 | 
						|
	{
 | 
						|
		if ((nTab1 < GetAllTabs().size()) && (nTab2 < GetAllTabs().size()) && (nTab1 != nTab2))
 | 
						|
		{
 | 
						|
			int nPage = GetCurSel();
 | 
						|
			TabPageInfo T1 = GetTabPageInfo(nTab1);
 | 
						|
			TabPageInfo T2 = GetTabPageInfo(nTab2);
 | 
						|
 | 
						|
			TCITEM Item1 = {0};
 | 
						|
			Item1.mask = TCIF_IMAGE | TCIF_PARAM | TCIF_RTLREADING | TCIF_STATE | TCIF_TEXT;
 | 
						|
			GetItem(nTab1, &Item1);
 | 
						|
			TCITEM Item2 = {0};
 | 
						|
			Item2.mask = TCIF_IMAGE | TCIF_PARAM | TCIF_RTLREADING | TCIF_STATE | TCIF_TEXT;
 | 
						|
			GetItem(nTab2, &Item2);
 | 
						|
			TabCtrl_SetItem(m_hWnd, nTab1, &Item2);
 | 
						|
			TabCtrl_SetItem(m_hWnd, nTab2, &Item1);
 | 
						|
 | 
						|
			m_vTabPageInfo[nTab1] = T2;
 | 
						|
			m_vTabPageInfo[nTab2] = T1;
 | 
						|
			SelectPage(nPage);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	inline LRESULT CTab::WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam)
 | 
						|
	{
 | 
						|
		switch(uMsg)
 | 
						|
		{
 | 
						|
		case WM_PAINT:
 | 
						|
			if (GetWindowLongPtr(GWL_STYLE) & TCS_OWNERDRAWFIXED)
 | 
						|
			{
 | 
						|
				// Remove all pending paint requests
 | 
						|
				PAINTSTRUCT ps;
 | 
						|
				BeginPaint(ps);
 | 
						|
				EndPaint(ps);
 | 
						|
 | 
						|
				// Now call our local Paint
 | 
						|
				Paint();
 | 
						|
				return 0;
 | 
						|
			}
 | 
						|
			break;
 | 
						|
 | 
						|
		case WM_ERASEBKGND:
 | 
						|
			if (GetWindowLongPtr(GWL_STYLE) & TCS_OWNERDRAWFIXED)
 | 
						|
				return 0;
 | 
						|
			break;
 | 
						|
		case WM_KILLFOCUS:
 | 
						|
			m_IsClosePressed = FALSE;
 | 
						|
			break;
 | 
						|
		case WM_LBUTTONDBLCLK:
 | 
						|
		case WM_LBUTTONDOWN:
 | 
						|
			OnLButtonDown(wParam, lParam);
 | 
						|
			break;
 | 
						|
		case WM_LBUTTONUP:
 | 
						|
			OnLButtonUp(wParam, lParam);
 | 
						|
			break;
 | 
						|
		case WM_MOUSEMOVE:
 | 
						|
			OnMouseMove(wParam, lParam);
 | 
						|
			break;
 | 
						|
		case WM_MOUSELEAVE:
 | 
						|
			OnMouseLeave(wParam, lParam);
 | 
						|
			break;
 | 
						|
		case WM_NCHITTEST:
 | 
						|
			return OnNCHitTest(wParam, lParam);
 | 
						|
 | 
						|
		case WM_WINDOWPOSCHANGING:
 | 
						|
			// A little hack to reduce tab flicker
 | 
						|
			if (IsWindowVisible() && (GetWindowLongPtr(GWL_STYLE) & TCS_OWNERDRAWFIXED))
 | 
						|
			{
 | 
						|
				LPWINDOWPOS pWinPos = (LPWINDOWPOS)lParam;
 | 
						|
				pWinPos->flags |= SWP_NOREDRAW;
 | 
						|
 | 
						|
				Paint();
 | 
						|
			}
 | 
						|
 | 
						|
			break;
 | 
						|
 | 
						|
		case WM_WINDOWPOSCHANGED:
 | 
						|
			RecalcLayout();
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		// pass unhandled messages on for default processing
 | 
						|
		return CWnd::WndProcDefault(uMsg, wParam, lParam);
 | 
						|
	}
 | 
						|
 | 
						|
	// Wrappers for Win32 Macros
 | 
						|
	inline void CTab::AdjustRect(BOOL fLarger, RECT *prc) const
 | 
						|
	{
 | 
						|
		assert(::IsWindow(m_hWnd));
 | 
						|
		TabCtrl_AdjustRect(m_hWnd, fLarger, prc);
 | 
						|
	}
 | 
						|
 | 
						|
	inline int CTab::GetCurFocus() const
 | 
						|
	{
 | 
						|
		assert(::IsWindow(m_hWnd));
 | 
						|
		return TabCtrl_GetCurFocus(m_hWnd);
 | 
						|
	}
 | 
						|
 | 
						|
	inline int CTab::GetCurSel() const
 | 
						|
	{
 | 
						|
		assert(::IsWindow(m_hWnd));
 | 
						|
		return TabCtrl_GetCurSel(m_hWnd);
 | 
						|
	}
 | 
						|
 | 
						|
	inline BOOL CTab::GetItem(int iItem, LPTCITEM pitem) const
 | 
						|
	{
 | 
						|
		assert(::IsWindow(m_hWnd));
 | 
						|
		return TabCtrl_GetItem(m_hWnd, iItem, pitem);
 | 
						|
	}
 | 
						|
 | 
						|
	inline int CTab::GetItemCount() const
 | 
						|
	{
 | 
						|
		assert(::IsWindow(m_hWnd));
 | 
						|
		return TabCtrl_GetItemCount(m_hWnd);
 | 
						|
	}
 | 
						|
 | 
						|
	inline int CTab::HitTest(TCHITTESTINFO& info) const
 | 
						|
	{
 | 
						|
		assert(::IsWindow(m_hWnd));
 | 
						|
		return TabCtrl_HitTest(m_hWnd, &info);
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTab::SetCurFocus(int iItem) const
 | 
						|
	{
 | 
						|
		assert(::IsWindow(m_hWnd));
 | 
						|
		TabCtrl_SetCurFocus(m_hWnd, iItem);
 | 
						|
	}
 | 
						|
 | 
						|
	inline int CTab::SetCurSel(int iItem) const
 | 
						|
	{
 | 
						|
		assert(::IsWindow(m_hWnd));
 | 
						|
		return TabCtrl_SetCurSel(m_hWnd, iItem);
 | 
						|
	}
 | 
						|
 | 
						|
	inline DWORD CTab::SetItemSize(int cx, int cy) const
 | 
						|
	{
 | 
						|
		assert(::IsWindow(m_hWnd));
 | 
						|
		return TabCtrl_SetItemSize(m_hWnd, cx, cy);
 | 
						|
	}
 | 
						|
 | 
						|
	inline int CTab::SetMinTabWidth(int cx) const
 | 
						|
	{
 | 
						|
		assert(::IsWindow(m_hWnd));
 | 
						|
		return TabCtrl_SetMinTabWidth(m_hWnd, cx);
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTab::SetPadding(int cx, int cy) const
 | 
						|
	{
 | 
						|
		assert(::IsWindow(m_hWnd));
 | 
						|
		TabCtrl_SetPadding(m_hWnd, cx, cy);
 | 
						|
	}
 | 
						|
 | 
						|
	////////////////////////////////////////
 | 
						|
	// Definitions for the CTabbedMDI class
 | 
						|
	inline CTabbedMDI::CTabbedMDI()
 | 
						|
	{
 | 
						|
		GetTab().SetShowButtons(TRUE);
 | 
						|
	}
 | 
						|
 | 
						|
	inline CTabbedMDI::~CTabbedMDI()
 | 
						|
	{
 | 
						|
	}
 | 
						|
 | 
						|
	inline CWnd* CTabbedMDI::AddMDIChild(CWnd* pView, LPCTSTR szTabText, int idMDIChild /*= 0*/)
 | 
						|
	{
 | 
						|
		assert(pView);
 | 
						|
		assert(lstrlen(szTabText) < MAX_MENU_STRING);
 | 
						|
 | 
						|
		GetTab().AddTabPage(WndPtr(pView), szTabText, 0, idMDIChild);
 | 
						|
 | 
						|
		// Fake a WM_MOUSEACTIVATE to propogate focus change to dockers
 | 
						|
		if (IsWindow())
 | 
						|
			GetParent()->SendMessage(WM_MOUSEACTIVATE, (WPARAM)GetAncestor(), MAKELPARAM(HTCLIENT,WM_LBUTTONDOWN));
 | 
						|
 | 
						|
		return pView;
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTabbedMDI::CloseActiveMDI()
 | 
						|
	{
 | 
						|
		int nTab = GetTab().GetCurSel();
 | 
						|
		if (nTab >= 0)
 | 
						|
			GetTab().RemoveTabPage(nTab);
 | 
						|
 | 
						|
		RecalcLayout();
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTabbedMDI::CloseAllMDIChildren()
 | 
						|
	{
 | 
						|
		while (GetMDIChildCount() > 0)
 | 
						|
		{
 | 
						|
			GetTab().RemoveTabPage(0);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTabbedMDI::CloseMDIChild(int nTab)
 | 
						|
	{
 | 
						|
		GetTab().RemoveTabPage(nTab);
 | 
						|
 | 
						|
		if (GetActiveMDIChild())
 | 
						|
			GetActiveMDIChild()->RedrawWindow();
 | 
						|
	}
 | 
						|
 | 
						|
	inline HWND CTabbedMDI::Create(CWnd* pParent /* = NULL*/)
 | 
						|
	{
 | 
						|
		CLIENTCREATESTRUCT clientcreate ;
 | 
						|
		clientcreate.hWindowMenu  = m_hWnd;
 | 
						|
		clientcreate.idFirstChild = IDW_FIRSTCHILD ;
 | 
						|
		DWORD dwStyle = WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES;
 | 
						|
 | 
						|
		// Create the MDICLIENT view window
 | 
						|
		if (!CreateEx(0, _T("MDICLIENT"), _T(""),
 | 
						|
			dwStyle, 0, 0, 0, 0, pParent, NULL, (PSTR) &clientcreate))
 | 
						|
				throw CWinException(_T("CMDIClient::Create ... CreateEx failed"));
 | 
						|
 | 
						|
		return m_hWnd;
 | 
						|
	}
 | 
						|
 | 
						|
	inline CWnd* CTabbedMDI::GetActiveMDIChild() const
 | 
						|
	{
 | 
						|
		CWnd* pView = NULL;
 | 
						|
		int nTab = GetTab().GetCurSel();
 | 
						|
		if (nTab >= 0)
 | 
						|
		{
 | 
						|
			TabPageInfo tbi = GetTab().GetTabPageInfo(nTab);
 | 
						|
			pView = tbi.pView;
 | 
						|
		}
 | 
						|
 | 
						|
		return pView;
 | 
						|
	}
 | 
						|
 | 
						|
	inline int CTabbedMDI::GetActiveMDITab() const
 | 
						|
	{
 | 
						|
		return GetTab().GetCurSel();
 | 
						|
	}
 | 
						|
 | 
						|
	inline CWnd* CTabbedMDI::GetMDIChild(int nTab) const
 | 
						|
	{
 | 
						|
		assert(nTab >= 0);
 | 
						|
		assert(nTab < GetMDIChildCount());
 | 
						|
		return GetTab().GetTabPageInfo(nTab).pView;
 | 
						|
	}
 | 
						|
 | 
						|
	inline int CTabbedMDI::GetMDIChildCount() const
 | 
						|
	{
 | 
						|
		return (int) GetTab().GetAllTabs().size();
 | 
						|
	}
 | 
						|
 | 
						|
	inline int   CTabbedMDI::GetMDIChildID(int nTab) const
 | 
						|
	{
 | 
						|
		assert(nTab >= 0);
 | 
						|
		assert(nTab < GetMDIChildCount());
 | 
						|
		return GetTab().GetTabPageInfo(nTab).idTab;
 | 
						|
	}
 | 
						|
 | 
						|
	inline LPCTSTR CTabbedMDI::GetMDIChildTitle(int nTab) const
 | 
						|
	{
 | 
						|
		assert(nTab >= 0);
 | 
						|
		assert(nTab < GetMDIChildCount());
 | 
						|
		return GetTab().GetTabPageInfo(nTab).szTabText;
 | 
						|
	}
 | 
						|
 | 
						|
	inline BOOL CTabbedMDI::LoadRegistrySettings(tString tsRegistryKeyName)
 | 
						|
	{
 | 
						|
		BOOL bResult = FALSE;
 | 
						|
 | 
						|
		if (0 != tsRegistryKeyName.size())
 | 
						|
		{
 | 
						|
			tString tsKey = _T("Software\\") + tsRegistryKeyName + _T("\\MDI Children");
 | 
						|
			HKEY hKey = 0;
 | 
						|
			RegOpenKeyEx(HKEY_CURRENT_USER, tsKey.c_str(), 0, KEY_READ, &hKey);
 | 
						|
			if (hKey)
 | 
						|
			{
 | 
						|
				DWORD dwType = REG_BINARY;
 | 
						|
				DWORD BufferSize = sizeof(TabPageInfo);
 | 
						|
				TabPageInfo tbi = {0};
 | 
						|
				int i = 0;
 | 
						|
				TCHAR szNumber[16];
 | 
						|
				tString tsSubKey = _T("MDI Child ");
 | 
						|
				tsSubKey += _itot(i, szNumber, 10);
 | 
						|
 | 
						|
				// Fill the DockList vector from the registry
 | 
						|
				while (0 == RegQueryValueEx(hKey, tsSubKey.c_str(), NULL, &dwType, (LPBYTE)&tbi, &BufferSize))
 | 
						|
				{
 | 
						|
					CWnd* pWnd = NewMDIChildFromID(tbi.idTab);
 | 
						|
					if (pWnd)
 | 
						|
					{
 | 
						|
						AddMDIChild(pWnd, tbi.szTabText, tbi.idTab);
 | 
						|
						i++;
 | 
						|
						tsSubKey = _T("MDI Child ");
 | 
						|
						tsSubKey += _itot(i, szNumber, 10);
 | 
						|
						bResult = TRUE;
 | 
						|
					}
 | 
						|
					else
 | 
						|
					{
 | 
						|
						TRACE(_T("Failed to get TabbedMDI info from registry"));
 | 
						|
						bResult = FALSE;
 | 
						|
						break;
 | 
						|
					}
 | 
						|
				}
 | 
						|
 | 
						|
				// Load Active MDI Tab from the registry
 | 
						|
				tsSubKey = _T("Active MDI Tab");
 | 
						|
				int nTab;
 | 
						|
				dwType = REG_DWORD;
 | 
						|
				BufferSize = sizeof(int);
 | 
						|
				if(ERROR_SUCCESS == RegQueryValueEx(hKey, tsSubKey.c_str(), NULL, &dwType, (LPBYTE)&nTab, &BufferSize))
 | 
						|
					SetActiveMDITab(nTab);
 | 
						|
				else
 | 
						|
					SetActiveMDITab(0);
 | 
						|
 | 
						|
				RegCloseKey(hKey);
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if (!bResult)
 | 
						|
			CloseAllMDIChildren();
 | 
						|
 | 
						|
		return bResult;
 | 
						|
	}
 | 
						|
 | 
						|
	inline CWnd* CTabbedMDI::NewMDIChildFromID(int /*idMDIChild*/)
 | 
						|
	{
 | 
						|
		// Override this function to create new MDI children from IDs as shown below
 | 
						|
		CWnd* pView = NULL;
 | 
						|
	/*	switch(idTab)
 | 
						|
		{
 | 
						|
		case ID_SIMPLE:
 | 
						|
			pView = new CViewSimple;
 | 
						|
			break;
 | 
						|
		case ID_RECT:
 | 
						|
			pView = new CViewRect;
 | 
						|
			break;
 | 
						|
		default:
 | 
						|
			TRACE(_T("Unknown MDI child ID\n"));
 | 
						|
			break;
 | 
						|
		} */
 | 
						|
 | 
						|
		return pView;
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTabbedMDI::OnCreate()
 | 
						|
	{
 | 
						|
		GetTab().Create(this);
 | 
						|
		GetTab().SetFixedWidth(TRUE);
 | 
						|
		GetTab().SetOwnerDraw(TRUE);
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTabbedMDI::OnDestroy(WPARAM /*wParam*/, LPARAM /*lParam*/ )
 | 
						|
	{
 | 
						|
		CloseAllMDIChildren();
 | 
						|
	}
 | 
						|
 | 
						|
	inline LRESULT CTabbedMDI::OnNotify(WPARAM /*wParam*/, LPARAM lParam)
 | 
						|
	{
 | 
						|
		LPNMHDR pnmhdr = (LPNMHDR)lParam;
 | 
						|
		if (pnmhdr->code == UWM_TAB_CHANGED)
 | 
						|
			RecalcLayout();
 | 
						|
 | 
						|
		return 0L;
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTabbedMDI::OnWindowPosChanged(WPARAM /*wParam*/, LPARAM /*lParam*/)
 | 
						|
	{
 | 
						|
		RecalcLayout();
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTabbedMDI::RecalcLayout()
 | 
						|
	{
 | 
						|
		if (GetTab().IsWindow())
 | 
						|
		{
 | 
						|
			if (GetTab().GetItemCount() >0)
 | 
						|
			{
 | 
						|
				CRect rcClient = GetClientRect();
 | 
						|
				GetTab().SetWindowPos(NULL, rcClient, SWP_SHOWWINDOW);
 | 
						|
				GetTab().UpdateWindow();
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				CRect rcClient = GetClientRect();
 | 
						|
				GetTab().SetWindowPos(NULL, rcClient, SWP_HIDEWINDOW);
 | 
						|
				Invalidate();
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	inline BOOL CTabbedMDI::SaveRegistrySettings(tString tsRegistryKeyName)
 | 
						|
	{
 | 
						|
		if (0 != tsRegistryKeyName.size())
 | 
						|
		{
 | 
						|
			tString tsKeyName = _T("Software\\") + tsRegistryKeyName;
 | 
						|
			HKEY hKey = NULL;
 | 
						|
			HKEY hKeyMDIChild = 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")));
 | 
						|
 | 
						|
				RegDeleteKey(hKey, _T("MDI Children"));
 | 
						|
				if (ERROR_SUCCESS != RegCreateKeyEx(hKey, _T("MDI Children"), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKeyMDIChild, NULL))
 | 
						|
					throw (CWinException(_T("RegCreateKeyEx Failed")));
 | 
						|
 | 
						|
				for (int i = 0; i < GetMDIChildCount(); ++i)
 | 
						|
				{
 | 
						|
					TCHAR szNumber[16];
 | 
						|
					tString tsSubKey = _T("MDI Child ");
 | 
						|
					tsSubKey += _itot(i, szNumber, 10);
 | 
						|
					TabPageInfo pdi = GetTab().GetTabPageInfo(i);
 | 
						|
					if (ERROR_SUCCESS != RegSetValueEx(hKeyMDIChild, tsSubKey.c_str(), 0, REG_BINARY, (LPBYTE)&pdi, sizeof(TabPageInfo)))
 | 
						|
						throw (CWinException(_T("RegSetValueEx Failed")));
 | 
						|
				}
 | 
						|
 | 
						|
				// Add Active Tab to the registry
 | 
						|
				tString tsSubKey = _T("Active MDI Tab");
 | 
						|
				int nTab = GetActiveMDITab();
 | 
						|
				if(ERROR_SUCCESS != RegSetValueEx(hKeyMDIChild, tsSubKey.c_str(), 0, REG_DWORD, (LPBYTE)&nTab, sizeof(int)))
 | 
						|
					throw (CWinException(_T("RegSetValueEx failed")));
 | 
						|
 | 
						|
				RegCloseKey(hKeyMDIChild);
 | 
						|
				RegCloseKey(hKey);
 | 
						|
			}
 | 
						|
			catch (const CWinException& e)
 | 
						|
			{
 | 
						|
				// Roll back the registry changes by deleting the subkeys
 | 
						|
				if (hKey)
 | 
						|
				{
 | 
						|
					if (hKeyMDIChild)
 | 
						|
					{
 | 
						|
						RegDeleteKey(hKeyMDIChild, _T("MDI Children"));
 | 
						|
						RegCloseKey(hKeyMDIChild);
 | 
						|
					}
 | 
						|
 | 
						|
					RegDeleteKey(HKEY_CURRENT_USER ,tsKeyName.c_str());
 | 
						|
					RegCloseKey(hKey);
 | 
						|
				}
 | 
						|
 | 
						|
				e.what();
 | 
						|
				return FALSE;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTabbedMDI::SetActiveMDIChild(CWnd* pWnd)
 | 
						|
	{
 | 
						|
		assert(pWnd);
 | 
						|
		int nPage = GetTab().GetTabIndex(pWnd);
 | 
						|
		if (nPage >= 0)
 | 
						|
			GetTab().SelectPage(nPage);
 | 
						|
	}
 | 
						|
 | 
						|
	inline void CTabbedMDI::SetActiveMDITab(int iTab)
 | 
						|
	{
 | 
						|
		assert(::IsWindow(m_hWnd));
 | 
						|
		assert(GetTab().IsWindow());
 | 
						|
		GetTab().SelectPage(iTab);
 | 
						|
	}
 | 
						|
 | 
						|
	inline LRESULT CTabbedMDI::WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam)
 | 
						|
	{
 | 
						|
		switch(uMsg)
 | 
						|
		{
 | 
						|
		case WM_DESTROY:
 | 
						|
			OnDestroy(wParam, lParam);
 | 
						|
			break;
 | 
						|
 | 
						|
		case WM_WINDOWPOSCHANGED:
 | 
						|
			OnWindowPosChanged(wParam, lParam);
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		return CWnd::WndProcDefault(uMsg, wParam, lParam);
 | 
						|
	}
 | 
						|
 | 
						|
} // namespace Win32xx
 | 
						|
 | 
						|
#endif  // _WIN32XX_TAB_H_
 |