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