1 // Win32++ Version 7.3
\r
2 // Released: 30th November 2011
\r
6 // url: https://sourceforge.net/projects/win32-framework
\r
9 // Copyright (c) 2005-2011 David Nash
\r
11 // Permission is hereby granted, free of charge, to
\r
12 // any person obtaining a copy of this software and
\r
13 // associated documentation files (the "Software"),
\r
14 // to deal in the Software without restriction, including
\r
15 // without limitation the rights to use, copy, modify,
\r
16 // merge, publish, distribute, sublicense, and/or sell
\r
17 // copies of the Software, and to permit persons to whom
\r
18 // the Software is furnished to do so, subject to the
\r
19 // following conditions:
\r
21 // The above copyright notice and this permission notice
\r
22 // shall be included in all copies or substantial portions
\r
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
\r
26 // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
\r
27 // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
\r
28 // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
\r
29 // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
\r
30 // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
\r
31 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
\r
32 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
\r
33 // OR OTHER DEALINGS IN THE SOFTWARE.
\r
35 ////////////////////////////////////////////////////////
\r
38 ///////////////////////////////////////////////////////
\r
40 // Declaration of the CTab and CMDITab classes
\r
42 #ifndef _WIN32XX_TAB_H_
\r
43 #define _WIN32XX_TAB_H_
\r
45 #include "wincore.h"
\r
48 #include "default_resource.h"
\r
55 TCHAR szTabText[MAX_MENU_STRING];
\r
56 int iImage; // index of this tab's image
\r
57 int idTab; // identifier for this tab (optional)
\r
58 CWnd* pView; // pointer to the view window
\r
61 class CTab : public CWnd
\r
64 // Declaration of the CSelectDialog class, a nested class of CTab
\r
65 // It creates the dialog to choose which tab to activate
\r
66 class CSelectDialog : public CDialog
\r
69 CSelectDialog(LPCDLGTEMPLATE lpTemplate, CWnd* pParent = NULL);
\r
70 virtual ~CSelectDialog() {}
\r
71 virtual void AddItem(LPCTSTR szString);
\r
72 virtual BOOL IsTab() const { return FALSE; }
\r
75 virtual BOOL OnInitDialog();
\r
76 virtual void OnOK();
\r
77 virtual void OnCancel() { EndDialog(-2); }
\r
80 CSelectDialog(const CSelectDialog&); // Disable copy construction
\r
81 CSelectDialog& operator = (const CSelectDialog&); // Disable assignment operator
\r
83 std::vector<CString> m_vItems;
\r
90 virtual int AddTabPage(WndPtr pView, LPCTSTR szTabText, HICON hIcon, UINT idTab);
\r
91 virtual int AddTabPage(WndPtr pView, LPCTSTR szTabText, int nID_Icon, UINT idTab = 0);
\r
92 virtual int AddTabPage(WndPtr pView, LPCTSTR szTabText);
\r
93 virtual CRect GetCloseRect() const;
\r
94 virtual CRect GetListRect() const;
\r
95 virtual HMENU GetListMenu();
\r
96 virtual BOOL GetTabsAtTop() const;
\r
97 virtual int GetTabIndex(CWnd* pWnd) const;
\r
98 virtual TabPageInfo GetTabPageInfo(UINT nTab) const;
\r
99 virtual int GetTextHeight() const;
\r
100 virtual void RecalcLayout();
\r
101 virtual void RemoveTabPage(int nPage);
\r
102 virtual void SelectPage(int nPage);
\r
103 virtual void SetFixedWidth(BOOL bEnabled);
\r
104 virtual void SetOwnerDraw(BOOL bEnabled);
\r
105 virtual void SetShowButtons(BOOL bShow);
\r
106 virtual void SetTabIcon(int i, HICON hIcon);
\r
107 virtual void SetTabsAtTop(BOOL bTop);
\r
108 virtual void SetTabText(UINT nTab, LPCTSTR szText);
\r
109 virtual void SwapTabs(UINT nTab1, UINT nTab2);
\r
112 std::vector <TabPageInfo>& GetAllTabs() const { return (std::vector <TabPageInfo>&) m_vTabPageInfo; }
\r
113 HIMAGELIST GetImageList() const { return m_himlTab; }
\r
114 BOOL GetShowButtons() const { return m_bShowButtons; }
\r
115 int GetTabHeight() const { return m_nTabHeight; }
\r
116 CWnd* GetActiveView() const { return m_pActiveView; }
\r
117 void SetTabHeight(int nTabHeight) { m_nTabHeight = nTabHeight; NotifyChanged();}
\r
119 // Wrappers for Win32 Macros
\r
120 void AdjustRect(BOOL fLarger, RECT *prc) const;
\r
121 int GetCurFocus() const;
\r
122 int GetCurSel() const;
\r
123 BOOL GetItem(int iItem, LPTCITEM pitem) const;
\r
124 int GetItemCount() const;
\r
125 int HitTest(TCHITTESTINFO& info) const;
\r
126 void SetCurFocus(int iItem) const;
\r
127 int SetCurSel(int iItem) const;
\r
128 DWORD SetItemSize(int cx, int cy) const;
\r
129 int SetMinTabWidth(int cx) const;
\r
130 void SetPadding(int cx, int cy) const;
\r
133 virtual void DrawCloseButton(CDC& DrawDC);
\r
134 virtual void DrawListButton(CDC& DrawDC);
\r
135 virtual void DrawTabs(CDC& dcMem);
\r
136 virtual void DrawTabBorders(CDC& dcMem, CRect& rcTab);
\r
137 virtual void OnCreate();
\r
138 virtual void OnLButtonDown(WPARAM wParam, LPARAM lParam);
\r
139 virtual void OnLButtonUp(WPARAM wParam, LPARAM lParam);
\r
140 virtual void OnMouseLeave(WPARAM wParam, LPARAM lParam);
\r
141 virtual void OnMouseMove(WPARAM wParam, LPARAM lParam);
\r
142 virtual LRESULT OnNCHitTest(WPARAM wParam, LPARAM lParam);
\r
143 virtual LRESULT OnNotifyReflect(WPARAM wParam, LPARAM lParam);
\r
144 virtual void NotifyChanged();
\r
145 virtual void Paint();
\r
146 virtual void PreCreate(CREATESTRUCT& cs);
\r
147 virtual void PreRegisterClass(WNDCLASS &wc);
\r
148 virtual void SetTabSize();
\r
149 virtual void ShowListDialog();
\r
150 virtual void ShowListMenu();
\r
151 virtual LRESULT WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam);
\r
154 CTab(const CTab&); // Disable copy construction
\r
155 CTab& operator = (const CTab&); // Disable assignment operator
\r
157 SIZE GetMaxTabSize() const;
\r
158 void ShowActiveView(CWnd* pView);
\r
160 std::vector<TabPageInfo> m_vTabPageInfo;
\r
161 std::vector<WndPtr> m_vTabViews;
\r
163 HIMAGELIST m_himlTab;
\r
165 CWnd* m_pActiveView;
\r
166 BOOL m_bShowButtons; // Show or hide the close and list button
\r
168 BOOL m_IsClosePressed;
\r
169 BOOL m_IsListPressed;
\r
170 BOOL m_IsListMenuActive;
\r
174 ////////////////////////////////////////
\r
175 // Declaration of the CTabbedMDI class
\r
176 class CTabbedMDI : public CWnd
\r
180 virtual ~CTabbedMDI();
\r
181 virtual CWnd* AddMDIChild(CWnd* pView, LPCTSTR szTabText, int idMDIChild = 0);
\r
182 virtual void CloseActiveMDI();
\r
183 virtual void CloseAllMDIChildren();
\r
184 virtual void CloseMDIChild(int nTab);
\r
185 virtual CWnd* GetActiveMDIChild() const;
\r
186 virtual int GetActiveMDITab() const;
\r
187 virtual CWnd* GetMDIChild(int nTab) const;
\r
188 virtual int GetMDIChildCount() const;
\r
189 virtual int GetMDIChildID(int nTab) const;
\r
190 virtual LPCTSTR GetMDIChildTitle(int nTab) const;
\r
191 virtual HMENU GetListMenu() const { return GetTab().GetListMenu(); }
\r
192 virtual CTab& GetTab() const {return (CTab&)m_Tab;}
\r
193 virtual BOOL LoadRegistrySettings(CString strRegistryKeyName);
\r
194 virtual void RecalcLayout();
\r
195 virtual BOOL SaveRegistrySettings(CString strRegistryKeyName);
\r
196 virtual void SetActiveMDIChild(CWnd* pWnd);
\r
197 virtual void SetActiveMDITab(int nTab);
\r
200 virtual HWND Create(CWnd* pParent);
\r
201 virtual CWnd* NewMDIChildFromID(int idMDIChild);
\r
202 virtual void OnCreate();
\r
203 virtual void OnDestroy(WPARAM wParam, LPARAM lParam);
\r
204 virtual LRESULT OnNotify(WPARAM wParam, LPARAM lParam);
\r
205 virtual void OnWindowPosChanged(WPARAM wParam, LPARAM lParam);
\r
206 virtual LRESULT WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam);
\r
209 CTabbedMDI(const CTabbedMDI&); // Disable copy construction
\r
210 CTabbedMDI& operator = (const CTabbedMDI&); // Disable assignment operator
\r
218 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\r
224 /////////////////////////////////////////////////////////////
\r
225 // Definitions for the CSelectDialog class nested within CTab
\r
227 inline CTab::CSelectDialog::CSelectDialog(LPCDLGTEMPLATE lpTemplate, CWnd* pParent) :
\r
228 CDialog(lpTemplate, pParent), IDC_LIST(121)
\r
232 inline BOOL CTab::CSelectDialog::OnInitDialog()
\r
234 for (UINT u = 0; u < m_vItems.size(); ++u)
\r
236 SendDlgItemMessage(IDC_LIST, LB_ADDSTRING, 0, (LPARAM) m_vItems[u].c_str());
\r
242 inline void CTab::CSelectDialog::AddItem(LPCTSTR szString)
\r
244 m_vItems.push_back(szString);
\r
247 inline void CTab::CSelectDialog::OnOK()
\r
249 int iSelect = (int)SendDlgItemMessage(IDC_LIST, LB_GETCURSEL, 0, 0);
\r
250 if (iSelect != LB_ERR)
\r
251 EndDialog(iSelect);
\r
257 //////////////////////////////////////////////////////////
\r
258 // Definitions for the CTab class
\r
260 inline CTab::CTab() : m_hListMenu(NULL), m_pActiveView(NULL), m_bShowButtons(FALSE), m_IsTracking(FALSE), m_IsClosePressed(FALSE),
\r
261 m_IsListPressed(FALSE), m_IsListMenuActive(FALSE), m_nTabHeight(0)
\r
263 // Create and assign the image list
\r
264 m_himlTab = ImageList_Create(16, 16, ILC_MASK|ILC_COLOR32, 0, 0);
\r
266 // Set the tab control's font
\r
267 NONCLIENTMETRICS info = {0};
\r
268 info.cbSize = GetSizeofNonClientMetrics();
\r
269 SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0);
\r
270 m_Font.CreateFontIndirect(&info.lfStatusFont);
\r
273 inline CTab::~CTab()
\r
275 ImageList_Destroy(m_himlTab);
\r
277 if (IsMenu(m_hListMenu)) ::DestroyMenu(m_hListMenu);
\r
280 inline int CTab::AddTabPage(WndPtr pView, LPCTSTR szTabText, HICON hIcon, UINT idTab)
\r
282 assert(pView.get());
\r
283 assert(lstrlen(szTabText) < MAX_MENU_STRING);
\r
285 m_vTabViews.push_back(pView);
\r
287 TabPageInfo tpi = {0};
\r
288 tpi.pView = pView.get();
\r
290 lstrcpyn(tpi.szTabText, szTabText, MAX_MENU_STRING);
\r
292 tpi.iImage = ImageList_AddIcon(GetImageList(), hIcon);
\r
296 int iNewPage = (int)m_vTabPageInfo.size();
\r
297 m_vTabPageInfo.push_back(tpi);
\r
302 tie.mask = TCIF_TEXT | TCIF_IMAGE;
\r
303 tie.iImage = tpi.iImage;
\r
304 tie.pszText = tpi.szTabText;
\r
305 TabCtrl_InsertItem(m_hWnd, iNewPage, &tie);
\r
308 SelectPage(iNewPage);
\r
315 inline int CTab::AddTabPage(WndPtr pView, LPCTSTR szTabText, int idIcon, UINT idTab /* = 0*/)
\r
317 HICON hIcon = (HICON)LoadImage(GetApp()->GetResourceHandle(), MAKEINTRESOURCE(idIcon), IMAGE_ICON, 0, 0, LR_SHARED);
\r
318 return AddTabPage(pView, szTabText, hIcon, idTab);
\r
321 inline int CTab::AddTabPage(WndPtr pView, LPCTSTR szTabText)
\r
323 return AddTabPage(pView, szTabText, (HICON)0, 0);
\r
326 inline void CTab::DrawCloseButton(CDC& DrawDC)
\r
328 // The close button isn't displayed on Win95
\r
329 if (GetWinVersion() == 1400) return;
\r
331 if (!m_bShowButtons) return;
\r
332 if (!GetActiveView()) return;
\r
333 if (!(GetWindowLongPtr(GWL_STYLE) & TCS_FIXEDWIDTH)) return;
\r
334 if (!(GetWindowLongPtr(GWL_STYLE) & TCS_OWNERDRAWFIXED)) return;
\r
336 // Determine the close button's drawing position relative to the window
\r
337 CRect rcClose = GetCloseRect();
\r
339 CPoint pt = GetCursorPos();
\r
340 ScreenToClient(pt);
\r
341 UINT uState = rcClose.PtInRect(pt)? m_IsClosePressed? 2: 1: 0;
\r
343 // Draw the outer highlight for the close button
\r
344 if (!IsRectEmpty(&rcClose))
\r
350 DrawDC.CreatePen(PS_SOLID, 1, RGB(232, 228, 220));
\r
352 DrawDC.MoveTo(rcClose.left, rcClose.bottom);
\r
353 DrawDC.LineTo(rcClose.right, rcClose.bottom);
\r
354 DrawDC.LineTo(rcClose.right, rcClose.top);
\r
355 DrawDC.LineTo(rcClose.left, rcClose.top);
\r
356 DrawDC.LineTo(rcClose.left, rcClose.bottom);
\r
362 // Draw outline, white at top, black on bottom
\r
363 DrawDC.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
\r
364 DrawDC.MoveTo(rcClose.left, rcClose.bottom);
\r
365 DrawDC.LineTo(rcClose.right, rcClose.bottom);
\r
366 DrawDC.LineTo(rcClose.right, rcClose.top);
\r
367 DrawDC.CreatePen(PS_SOLID, 1, RGB(255, 255, 255));
\r
368 DrawDC.LineTo(rcClose.left, rcClose.top);
\r
369 DrawDC.LineTo(rcClose.left, rcClose.bottom);
\r
375 // Draw outline, black on top, white on bottom
\r
376 DrawDC.CreatePen(PS_SOLID, 1, RGB(255, 255, 255));
\r
377 DrawDC.MoveTo(rcClose.left, rcClose.bottom);
\r
378 DrawDC.LineTo(rcClose.right, rcClose.bottom);
\r
379 DrawDC.LineTo(rcClose.right, rcClose.top);
\r
380 DrawDC.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
\r
381 DrawDC.LineTo(rcClose.left, rcClose.top);
\r
382 DrawDC.LineTo(rcClose.left, rcClose.bottom);
\r
387 // Manually draw close button
\r
388 DrawDC.CreatePen(PS_SOLID, 1, RGB(64, 64, 64));
\r
390 DrawDC.MoveTo(rcClose.left + 3, rcClose.top +3);
\r
391 DrawDC.LineTo(rcClose.right - 2, rcClose.bottom -2);
\r
393 DrawDC.MoveTo(rcClose.left + 4, rcClose.top +3);
\r
394 DrawDC.LineTo(rcClose.right - 2, rcClose.bottom -3);
\r
396 DrawDC.MoveTo(rcClose.left + 3, rcClose.top +4);
\r
397 DrawDC.LineTo(rcClose.right - 3, rcClose.bottom -2);
\r
399 DrawDC.MoveTo(rcClose.right -3, rcClose.top +3);
\r
400 DrawDC.LineTo(rcClose.left + 2, rcClose.bottom -2);
\r
402 DrawDC.MoveTo(rcClose.right -3, rcClose.top +4);
\r
403 DrawDC.LineTo(rcClose.left + 3, rcClose.bottom -2);
\r
405 DrawDC.MoveTo(rcClose.right -4, rcClose.top +3);
\r
406 DrawDC.LineTo(rcClose.left + 2, rcClose.bottom -3);
\r
410 inline void CTab::DrawListButton(CDC& DrawDC)
\r
412 // The list button isn't displayed on Win95
\r
413 if (GetWinVersion() == 1400) return;
\r
415 if (!m_bShowButtons) return;
\r
416 if (!GetActiveView()) return;
\r
417 if (!(GetWindowLongPtr(GWL_STYLE) & TCS_FIXEDWIDTH)) return;
\r
418 if (!(GetWindowLongPtr(GWL_STYLE) & TCS_OWNERDRAWFIXED)) return;
\r
420 // Determine the list button's drawing position relative to the window
\r
421 CRect rcList = GetListRect();
\r
423 CPoint pt = GetCursorPos();
\r
424 ScreenToClient(pt);
\r
425 UINT uState = rcList.PtInRect(pt)? 1: 0;
\r
426 if (m_IsListMenuActive) uState = 2;
\r
428 // Draw the outer highlight for the list button
\r
429 if (!IsRectEmpty(&rcList))
\r
435 DrawDC.CreatePen(PS_SOLID, 1, RGB(232, 228, 220));
\r
437 DrawDC.MoveTo(rcList.left, rcList.bottom);
\r
438 DrawDC.LineTo(rcList.right, rcList.bottom);
\r
439 DrawDC.LineTo(rcList.right, rcList.top);
\r
440 DrawDC.LineTo(rcList.left, rcList.top);
\r
441 DrawDC.LineTo(rcList.left, rcList.bottom);
\r
447 // Draw outline, white at top, black on bottom
\r
448 DrawDC.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
\r
449 DrawDC.MoveTo(rcList.left, rcList.bottom);
\r
450 DrawDC.LineTo(rcList.right, rcList.bottom);
\r
451 DrawDC.LineTo(rcList.right, rcList.top);
\r
452 DrawDC.CreatePen(PS_SOLID, 1, RGB(255, 255, 255));
\r
453 DrawDC.LineTo(rcList.left, rcList.top);
\r
454 DrawDC.LineTo(rcList.left, rcList.bottom);
\r
460 // Draw outline, black on top, white on bottom
\r
461 DrawDC.CreatePen(PS_SOLID, 1, RGB(255, 255, 255));
\r
462 DrawDC.MoveTo(rcList.left, rcList.bottom);
\r
463 DrawDC.LineTo(rcList.right, rcList.bottom);
\r
464 DrawDC.LineTo(rcList.right, rcList.top);
\r
465 DrawDC.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
\r
466 DrawDC.LineTo(rcList.left, rcList.top);
\r
467 DrawDC.LineTo(rcList.left, rcList.bottom);
\r
472 // Manually draw list button
\r
473 DrawDC.CreatePen(PS_SOLID, 1, RGB(64, 64, 64));
\r
475 int MaxLength = (int)(0.65 * rcList.Width());
\r
476 int topGap = 1 + rcList.Height()/3;
\r
477 for (int i = 0; i <= MaxLength/2; i++)
\r
479 int Length = MaxLength - 2*i;
\r
480 DrawDC.MoveTo(rcList.left +1 + (rcList.Width() - Length)/2, rcList.top +topGap +i);
\r
481 DrawDC.LineTo(rcList.left +1 + (rcList.Width() - Length)/2 + Length, rcList.top +topGap +i);
\r
486 inline void CTab::DrawTabs(CDC& dcMem)
\r
488 // Draw the tab buttons:
\r
489 for (int i = 0; i < TabCtrl_GetItemCount(m_hWnd); ++i)
\r
492 TabCtrl_GetItemRect(m_hWnd, i, &rcItem);
\r
493 if (!rcItem.IsRectEmpty())
\r
495 if (i == TabCtrl_GetCurSel(m_hWnd))
\r
497 dcMem.CreateSolidBrush(RGB(248,248,248));
\r
498 dcMem.SetBkColor(RGB(248,248,248));
\r
502 dcMem.CreateSolidBrush(RGB(200,200,200));
\r
503 dcMem.SetBkColor(RGB(200,200,200));
\r
506 dcMem.CreatePen(PS_SOLID, 1, RGB(160, 160, 160));
\r
507 dcMem.RoundRect(rcItem.left+1, rcItem.top, rcItem.right+2, rcItem.bottom, 6, 6);
\r
509 if (rcItem.Width() >= 24)
\r
512 TCITEM tcItem = {0};
\r
513 tcItem.mask = TCIF_TEXT | TCIF_IMAGE;
\r
514 tcItem.cchTextMax = 30;
\r
515 tcItem.pszText = szText;
\r
516 TabCtrl_GetItem(m_hWnd, i, &tcItem);
\r
520 if (ImageList_GetIconSize(m_himlTab, &xImage, &yImage))
\r
521 yOffset = (rcItem.Height() - yImage)/2;
\r
524 ImageList_Draw(m_himlTab, tcItem.iImage, dcMem, rcItem.left+5, rcItem.top+yOffset, ILD_NORMAL);
\r
527 ::SelectObject(dcMem, m_Font);
\r
529 // Calculate the size of the text
\r
530 CRect rcText = rcItem;
\r
532 int iImageSize = 20;
\r
534 if (tcItem.iImage >= 0)
\r
535 rcText.left += iImageSize;
\r
537 rcText.left += iPadding;
\r
538 dcMem.DrawText(szText, -1, rcText, DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_END_ELLIPSIS);
\r
544 inline void CTab::DrawTabBorders(CDC& dcMem, CRect& rcTab)
\r
546 BOOL IsBottomTab = (BOOL)GetWindowLongPtr(GWL_STYLE) & TCS_BOTTOM;
\r
548 // Draw a lighter rectangle touching the tab buttons
\r
550 TabCtrl_GetItemRect(m_hWnd, 0, &rcItem);
\r
551 int left = rcItem.left +1;
\r
552 int right = rcTab.right;
\r
553 int top = rcTab.bottom;
\r
554 int bottom = top + 3;
\r
558 bottom = MAX(rcTab.top, m_nTabHeight +4);
\r
562 dcMem.CreateSolidBrush(RGB(248,248,248));
\r
563 dcMem.CreatePen(PS_SOLID, 1, RGB(248,248,248));
\r
564 if (!rcItem.IsRectEmpty())
\r
566 dcMem.Rectangle(left, top, right, bottom);
\r
568 // Draw a darker line below the rectangle
\r
569 dcMem.CreatePen(PS_SOLID, 1, RGB(160, 160, 160));
\r
572 dcMem.MoveTo(left-1, bottom);
\r
573 dcMem.LineTo(right, bottom);
\r
577 dcMem.MoveTo(left-1, top-1);
\r
578 dcMem.LineTo(right, top-1);
\r
581 // Draw a lighter line over the darker line for the selected tab
\r
582 dcMem.CreatePen(PS_SOLID, 1, RGB(248,248,248));
\r
583 TabCtrl_GetItemRect(m_hWnd, TabCtrl_GetCurSel(m_hWnd), &rcItem);
\r
584 OffsetRect(&rcItem, 1, 1);
\r
588 dcMem.MoveTo(rcItem.left, bottom);
\r
589 dcMem.LineTo(rcItem.right, bottom);
\r
593 dcMem.MoveTo(rcItem.left, top-1);
\r
594 dcMem.LineTo(rcItem.right, top-1);
\r
599 inline CRect CTab::GetCloseRect() const
\r
602 if (GetShowButtons())
\r
604 rcClose= GetClientRect();
\r
606 int cx = GetSystemMetrics(SM_CXSMICON) -1;
\r
607 int cy = GetSystemMetrics(SM_CYSMICON) -1;
\r
608 rcClose.right -= Gap;
\r
609 rcClose.left = rcClose.right - cx;
\r
611 if (GetTabsAtTop())
\r
614 rcClose.top = MAX(Gap, rcClose.bottom - m_nTabHeight);
\r
616 rcClose.bottom = rcClose.top + cy;
\r
621 inline HMENU CTab::GetListMenu()
\r
623 if (IsMenu(m_hListMenu))
\r
624 ::DestroyMenu(m_hListMenu);
\r
626 m_hListMenu = CreatePopupMenu();
\r
628 // Add the menu items
\r
629 for(UINT u = 0; u < MIN(GetAllTabs().size(), 9); ++u)
\r
631 TCHAR szMenuString[MAX_MENU_STRING+1];
\r
632 TCHAR szTabText[MAX_MENU_STRING];
\r
633 lstrcpyn(szTabText, GetAllTabs()[u].szTabText, MAX_MENU_STRING -4);
\r
634 wsprintf(szMenuString, _T("&%d %s"), u+1, szTabText);
\r
635 AppendMenu(m_hListMenu, MF_STRING, IDW_FIRSTCHILD +u, szMenuString);
\r
637 if (GetAllTabs().size() >= 10)
\r
638 AppendMenu(m_hListMenu, MF_STRING, IDW_FIRSTCHILD +9, _T("More Windows"));
\r
640 // Add a checkmark to the menu
\r
641 int iSelected = GetCurSel();
\r
643 CheckMenuItem(m_hListMenu, iSelected, MF_BYPOSITION|MF_CHECKED);
\r
645 return m_hListMenu;
\r
648 inline CRect CTab::GetListRect() const
\r
651 if (GetShowButtons())
\r
653 CRect rcClose = GetCloseRect();
\r
655 rcList.OffsetRect( -(rcClose.Width() + 2), 0);
\r
656 rcList.InflateRect(-1, 0);
\r
661 inline SIZE CTab::GetMaxTabSize() const
\r
665 for (int i = 0; i < TabCtrl_GetItemCount(m_hWnd); i++)
\r
667 CClientDC dcClient(this);
\r
668 ::SelectObject(dcClient, m_Font);
\r
669 std::vector<TCHAR> vTitle(MAX_MENU_STRING, _T('\0'));
\r
670 TCHAR* pszTitle = &vTitle.front();
\r
671 TCITEM tcItem = {0};
\r
672 tcItem.mask = TCIF_TEXT |TCIF_IMAGE;
\r
673 tcItem.cchTextMax = MAX_MENU_STRING;
\r
674 tcItem.pszText = pszTitle;
\r
675 TabCtrl_GetItem(m_hWnd, i, &tcItem);
\r
676 CSize TempSize = dcClient.GetTextExtentPoint32(pszTitle, lstrlen(pszTitle));
\r
678 int iImageSize = 0;
\r
680 if (tcItem.iImage >= 0)
\r
682 TempSize.cx += iImageSize + iPadding;
\r
684 if (TempSize.cx > Size.cx)
\r
691 inline BOOL CTab::GetTabsAtTop() const
\r
692 // Returns TRUE if the contol's tabs are placed at the top
\r
694 DWORD dwStyle = (DWORD)GetWindowLongPtr(GWL_STYLE);
\r
695 return (!(dwStyle & TCS_BOTTOM));
\r
698 inline int CTab::GetTextHeight() const
\r
700 CClientDC dcClient(this);
\r
701 ::SelectObject(dcClient, m_Font);
\r
702 CSize szText = dcClient.GetTextExtentPoint32(_T("Text"), lstrlen(_T("Text")));
\r
706 inline int CTab::GetTabIndex(CWnd* pWnd) const
\r
710 for (int i = 0; i < (int)m_vTabPageInfo.size(); ++i)
\r
712 if (m_vTabPageInfo[i].pView == pWnd)
\r
719 inline TabPageInfo CTab::GetTabPageInfo(UINT nTab) const
\r
721 assert (nTab < m_vTabPageInfo.size());
\r
723 return m_vTabPageInfo[nTab];
\r
726 inline void CTab::NotifyChanged()
\r
729 nmhdr.hwndFrom = m_hWnd;
\r
730 nmhdr.code = UWM_TAB_CHANGED;
\r
731 GetParent()->SendMessage(WM_NOTIFY, 0L, (LPARAM)&nmhdr);
\r
734 inline void CTab::OnCreate()
\r
736 SetFont(&m_Font, TRUE);
\r
738 // Assign ImageList unless we are owner drawn
\r
739 if (!(GetWindowLongPtr(GWL_STYLE) & TCS_OWNERDRAWFIXED))
\r
740 TabCtrl_SetImageList(m_hWnd, m_himlTab);
\r
742 for (int i = 0; i < (int)m_vTabPageInfo.size(); ++i)
\r
744 // Add tabs for each view.
\r
746 tie.mask = TCIF_TEXT | TCIF_IMAGE;
\r
747 tie.iImage = m_vTabPageInfo[i].iImage;
\r
748 tie.pszText = m_vTabPageInfo[i].szTabText;
\r
749 TabCtrl_InsertItem(m_hWnd, i, &tie);
\r
753 SetTabHeight(MAX(20, (GetTextHeight() + HeightGap)));
\r
757 inline void CTab::OnLButtonDown(WPARAM /*wParam*/, LPARAM lParam)
\r
759 CPoint pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
\r
761 if (GetCloseRect().PtInRect(pt))
\r
763 m_IsClosePressed = TRUE;
\r
765 CClientDC dc(this);
\r
766 DrawCloseButton(dc);
\r
769 m_IsClosePressed = FALSE;
\r
771 if (GetListRect().PtInRect(pt))
\r
777 inline void CTab::OnLButtonUp(WPARAM /*wParam*/, LPARAM lParam)
\r
780 CPoint pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
\r
781 if (m_IsClosePressed && GetCloseRect().PtInRect(pt))
\r
783 RemoveTabPage(GetCurSel());
\r
784 if (GetActiveView())
\r
785 GetActiveView()->RedrawWindow();
\r
788 m_IsClosePressed = FALSE;
\r
791 inline void CTab::OnMouseLeave(WPARAM /*wParam*/, LPARAM /*lParam*/)
\r
793 CClientDC dc(this);
\r
794 DrawCloseButton(dc);
\r
795 DrawListButton(dc);
\r
797 m_IsTracking = FALSE;
\r
800 inline void CTab::OnMouseMove(WPARAM /*wParam*/, LPARAM /*lParam*/)
\r
802 if (!m_IsListMenuActive && m_IsListPressed)
\r
804 m_IsListPressed = FALSE;
\r
809 TRACKMOUSEEVENT TrackMouseEventStruct = {0};
\r
810 TrackMouseEventStruct.cbSize = sizeof(TrackMouseEventStruct);
\r
811 TrackMouseEventStruct.dwFlags = TME_LEAVE;
\r
812 TrackMouseEventStruct.hwndTrack = m_hWnd;
\r
813 _TrackMouseEvent(&TrackMouseEventStruct);
\r
814 m_IsTracking = TRUE;
\r
817 CClientDC dc(this);
\r
818 DrawCloseButton(dc);
\r
819 DrawListButton(dc);
\r
822 inline LRESULT CTab::OnNCHitTest(WPARAM wParam, LPARAM lParam)
\r
824 // Ensure we have an arrow cursor when the tab has no view window
\r
825 if (0 == GetAllTabs().size())
\r
826 SetCursor(LoadCursor(NULL, IDC_ARROW));
\r
828 // Cause WM_LBUTTONUP and WM_LBUTTONDOWN messages to be sent for buttons
\r
829 CPoint pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
\r
830 ScreenToClient(pt);
\r
831 if (GetCloseRect().PtInRect(pt)) return HTCLIENT;
\r
832 if (GetListRect().PtInRect(pt)) return HTCLIENT;
\r
834 return CWnd::WndProcDefault(WM_NCHITTEST, wParam, lParam);
\r
837 inline LRESULT CTab::OnNotifyReflect(WPARAM wParam, LPARAM lParam)
\r
839 UNREFERENCED_PARAMETER(wParam);
\r
841 switch (((LPNMHDR)lParam)->code)
\r
843 case TCN_SELCHANGE:
\r
845 // Display the newly selected tab page
\r
846 int nPage = GetCurSel();
\r
847 ShowActiveView(m_vTabPageInfo[nPage].pView);
\r
855 inline void CTab::Paint()
\r
857 // Microsoft's drawing for a tab control is rubbish, so we do our own.
\r
858 // We use double buffering and regions to eliminate flicker
\r
860 // Create the memory DC and bitmap
\r
861 CClientDC dcView(this);
\r
862 CMemDC dcMem(&dcView);
\r
863 CRect rcClient = GetClientRect();
\r
864 dcMem.CreateCompatibleBitmap(&dcView, rcClient.Width(), rcClient.Height());
\r
866 if (0 == GetItemCount())
\r
868 // No tabs, so simply display a grey background and exit
\r
869 COLORREF rgbDialog = GetSysColor(COLOR_BTNFACE);
\r
870 dcView.SolidFill(rgbDialog, rcClient);
\r
874 // Create a clipping region. Its the overall tab window's region,
\r
875 // less the region belonging to the individual tab view's client area
\r
876 CRgn rgnSrc1 = ::CreateRectRgn(rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
\r
877 CRect rcTab = GetClientRect();
\r
878 TabCtrl_AdjustRect(m_hWnd, FALSE, &rcTab);
\r
879 if (rcTab.Height() < 0)
\r
880 rcTab.top = rcTab.bottom;
\r
881 if (rcTab.Width() < 0)
\r
882 rcTab.left = rcTab.right;
\r
884 CRgn rgnSrc2 = ::CreateRectRgn(rcTab.left, rcTab.top, rcTab.right, rcTab.bottom);
\r
885 CRgn rgnClip = ::CreateRectRgn(0, 0, 0, 0);
\r
886 ::CombineRgn(rgnClip, rgnSrc1, rgnSrc2, RGN_DIFF);
\r
888 // Use the region in the memory DC to paint the grey background
\r
889 dcMem.SelectClipRgn(&rgnClip);
\r
890 HWND hWndParent = ::GetParent(m_hWnd);
\r
891 CDC dcParent = ::GetDC(hWndParent);
\r
892 HBRUSH hBrush = (HBRUSH) SendMessage(hWndParent, WM_CTLCOLORDLG, (WPARAM)dcParent.GetHDC(), (LPARAM)hWndParent);
\r
893 ::SelectObject(dcMem, hBrush);
\r
894 dcMem.PaintRgn(&rgnClip);
\r
896 // Draw the tab buttons on the memory DC:
\r
899 // Draw buttons and tab borders
\r
900 DrawCloseButton(dcMem);
\r
901 DrawListButton(dcMem);
\r
902 DrawTabBorders(dcMem, rcTab);
\r
904 // Now copy our from our memory DC to the window DC
\r
905 dcView.SelectClipRgn(&rgnClip);
\r
906 dcView.BitBlt(0, 0, rcClient.Width(), rcClient.Height(), &dcMem, 0, 0, SRCCOPY);
\r
909 inline void CTab::PreCreate(CREATESTRUCT &cs)
\r
911 // For Tabs on the bottom, add the TCS_BOTTOM style
\r
912 cs.style = WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE;
\r
915 inline void CTab::PreRegisterClass(WNDCLASS &wc)
\r
917 wc.lpszClassName = WC_TABCONTROL;
\r
920 inline void CTab::RecalcLayout()
\r
924 if (GetActiveView())
\r
926 // Set the tab sizes
\r
929 // Position the View over the tab control's display area
\r
930 CRect rc = GetClientRect();
\r
931 TabCtrl_AdjustRect(m_hWnd, FALSE, &rc);
\r
932 GetActiveView()->SetWindowPos(NULL, rc, SWP_SHOWWINDOW);
\r
939 inline void CTab::RemoveTabPage(int nPage)
\r
941 if ((nPage < 0) || (nPage > (int)m_vTabPageInfo.size() -1))
\r
945 TabCtrl_DeleteItem(m_hWnd, nPage);
\r
947 // Remove the TapPageInfo entry
\r
948 std::vector<TabPageInfo>::iterator itTPI = m_vTabPageInfo.begin() + nPage;
\r
949 CWnd* pView = (*itTPI).pView;
\r
950 int iImage = (*itTPI).iImage;
\r
952 TabCtrl_RemoveImage(m_hWnd, iImage);
\r
954 if (pView == m_pActiveView)
\r
957 (*itTPI).pView->Destroy();
\r
958 m_vTabPageInfo.erase(itTPI);
\r
960 std::vector<WndPtr>::iterator itView;
\r
961 for (itView = m_vTabViews.begin(); itView < m_vTabViews.end(); ++itView)
\r
963 if ((*itView).get() == pView)
\r
965 m_vTabViews.erase(itView);
\r
972 if (m_vTabPageInfo.size() > 0)
\r
978 ShowActiveView(NULL);
\r
984 inline void CTab::SelectPage(int nPage)
\r
986 if ((nPage >= 0) && (nPage < GetItemCount()))
\r
988 if (nPage != GetCurSel())
\r
991 ShowActiveView(m_vTabPageInfo[nPage].pView);
\r
995 inline void CTab::SetFixedWidth(BOOL bEnabled)
\r
997 DWORD dwStyle = (DWORD)GetWindowLongPtr(GWL_STYLE);
\r
999 SetWindowLongPtr(GWL_STYLE, dwStyle | TCS_FIXEDWIDTH);
\r
1001 SetWindowLongPtr(GWL_STYLE, dwStyle & ~TCS_FIXEDWIDTH);
\r
1006 inline void CTab::SetOwnerDraw(BOOL bEnabled)
\r
1007 // Enable or disable owner draw
\r
1009 DWORD dwStyle = (DWORD)GetWindowLongPtr(GWL_STYLE);
\r
1012 SetWindowLongPtr(GWL_STYLE, dwStyle | TCS_OWNERDRAWFIXED);
\r
1013 TabCtrl_SetImageList(m_hWnd, NULL);
\r
1017 SetWindowLongPtr(GWL_STYLE, dwStyle & ~TCS_OWNERDRAWFIXED);
\r
1018 TabCtrl_SetImageList(m_hWnd, m_himlTab);
\r
1024 inline void CTab::SetShowButtons(BOOL bShow)
\r
1026 m_bShowButtons = bShow;
\r
1030 inline void CTab::SetTabIcon(int i, HICON hIcon)
\r
1031 // Changes or sets the tab's icon
\r
1033 assert (GetItemCount() > i);
\r
1035 tci.mask = TCIF_IMAGE;
\r
1037 if (tci.iImage >= 0)
\r
1039 ImageList_ReplaceIcon(GetImageList(), i, hIcon);
\r
1043 int iImage = ImageList_AddIcon(GetImageList(), hIcon);
\r
1044 tci.iImage = iImage;
\r
1045 TabCtrl_SetItem(m_hWnd, i, &tci);
\r
1046 m_vTabPageInfo[i].iImage = iImage;
\r
1050 inline void CTab::SetTabsAtTop(BOOL bTop)
\r
1051 // Positions the tabs at the top or botttom of the control
\r
1053 DWORD dwStyle = (DWORD)GetWindowLongPtr(GWL_STYLE);
\r
1056 dwStyle &= ~TCS_BOTTOM;
\r
1058 dwStyle |= TCS_BOTTOM;
\r
1060 SetWindowLongPtr(GWL_STYLE, dwStyle);
\r
1064 inline void CTab::SetTabSize()
\r
1066 if (GetItemCount() > 0)
\r
1068 CRect rc = GetClientRect();
\r
1069 TabCtrl_AdjustRect(m_hWnd, FALSE, &rc);
\r
1072 if (m_bShowButtons) xGap += GetCloseRect().Width() + GetListRect().Width() +2;
\r
1074 int nItemWidth = MIN( GetMaxTabSize().cx, (rc.Width() - xGap)/GetItemCount() );
\r
1075 nItemWidth = MAX(nItemWidth, 0);
\r
1076 SendMessage(TCM_SETITEMSIZE, 0L, MAKELPARAM(nItemWidth, m_nTabHeight));
\r
1081 inline void CTab::SetTabText(UINT nTab, LPCTSTR szText)
\r
1083 // Allows the text to be changed on an existing tab
\r
1084 if (nTab < GetAllTabs().size())
\r
1086 TCITEM Item = {0};
\r
1087 std::vector<TCHAR> vTChar(MAX_MENU_STRING+1, _T('\0'));
\r
1088 TCHAR* pTChar = &vTChar.front();
\r
1089 lstrcpyn(pTChar, szText, MAX_MENU_STRING);
\r
1090 Item.mask = TCIF_TEXT;
\r
1091 Item.pszText = pTChar;
\r
1093 if (TabCtrl_SetItem(m_hWnd, nTab, &Item))
\r
1094 lstrcpyn(m_vTabPageInfo[nTab].szTabText, pTChar, MAX_MENU_STRING);
\r
1098 inline void CTab::ShowActiveView(CWnd* pView)
\r
1099 // Sets or changes the View window displayed within the tab page
\r
1101 // Hide the old view
\r
1102 if (GetActiveView() && (GetActiveView()->IsWindow()))
\r
1103 GetActiveView()->ShowWindow(SW_HIDE);
\r
1105 // Assign the view window
\r
1106 m_pActiveView = pView;
\r
1108 if (m_pActiveView && m_hWnd)
\r
1110 if (!m_pActiveView->IsWindow())
\r
1112 // The tab control is already created, so create the new view too
\r
1113 GetActiveView()->Create(this);
\r
1116 // Position the View over the tab control's display area
\r
1117 CRect rc = GetClientRect();
\r
1118 TabCtrl_AdjustRect(m_hWnd, FALSE, &rc);
\r
1119 GetActiveView()->SetWindowPos(0, rc, SWP_SHOWWINDOW);
\r
1120 GetActiveView()->SetFocus();
\r
1124 inline void CTab::ShowListMenu()
\r
1125 // Displays the list of windows in a popup menu
\r
1127 if (!m_IsListPressed)
\r
1129 m_IsListPressed = TRUE;
\r
1130 HMENU hMenu = GetListMenu();
\r
1132 CPoint pt(GetListRect().left, GetListRect().top + GetTabHeight());
\r
1133 ClientToScreen(pt);
\r
1135 // Choosing the frame's hwnd for the menu's messages will automatically theme the popup menu
\r
1136 HWND MenuHwnd = GetAncestor()->GetHwnd();
\r
1138 m_IsListMenuActive = TRUE;
\r
1139 nPage = TrackPopupMenuEx(hMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD, pt.x, pt.y, MenuHwnd, NULL) - IDW_FIRSTCHILD;
\r
1140 if ((nPage >= 0) && (nPage < 9)) SelectPage(nPage);
\r
1141 if (nPage == 9) ShowListDialog();
\r
1142 m_IsListMenuActive = FALSE;
\r
1145 CClientDC dc(this);
\r
1146 DrawListButton(dc);
\r
1149 inline void CTab::ShowListDialog()
\r
1151 // Definition of a dialog template which displays a List Box
\r
1152 unsigned char dlg_Template[] =
\r
1154 0x01,0x00,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0xc8,0x00,0xc8,0x90,0x03,
\r
1155 0x00,0x00,0x00,0x00,0x00,0xdc,0x00,0x8e,0x00,0x00,0x00,0x00,0x00,0x53,0x00,0x65,
\r
1156 0x00,0x6c,0x00,0x65,0x00,0x63,0x00,0x74,0x00,0x20,0x00,0x57,0x00,0x69,0x00,0x6e,
\r
1157 0x00,0x64,0x00,0x6f,0x00,0x77,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x01,0x4d,
\r
1158 0x00,0x53,0x00,0x20,0x00,0x53,0x00,0x68,0x00,0x65,0x00,0x6c,0x00,0x6c,0x00,0x20,
\r
1159 0x00,0x44,0x00,0x6c,0x00,0x67,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
\r
1160 0x00,0x00,0x00,0x01,0x00,0x01,0x50,0x40,0x00,0x7a,0x00,0x25,0x00,0x0f,0x00,0x01,
\r
1161 0x00,0x00,0x00,0xff,0xff,0x80,0x00,0x4f,0x00,0x4b,0x00,0x00,0x00,0x00,0x00,0x00,
\r
1162 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x50,0x7a,0x00,0x7a,0x00,0x25,
\r
1163 0x00,0x0f,0x00,0x02,0x00,0x00,0x00,0xff,0xff,0x80,0x00,0x43,0x00,0x61,0x00,0x6e,
\r
1164 0x00,0x63,0x00,0x65,0x00,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
\r
1165 0x00,0x02,0x00,0x01,0x01,0x21,0x50,0x06,0x00,0x06,0x00,0xcf,0x00,0x6d,0x00,0x79,
\r
1166 0x00,0x00,0x00,0xff,0xff,0x83,0x00,0x00,0x00,0x00,0x00
\r
1169 // Display the modal dialog. The dialog is defined in the dialog template rather
\r
1170 // than in the resource script (rc) file.
\r
1171 CSelectDialog MyDialog((LPCDLGTEMPLATE) dlg_Template);
\r
1172 for(UINT u = 0; u < GetAllTabs().size(); ++u)
\r
1174 MyDialog.AddItem(GetAllTabs()[u].szTabText);
\r
1177 int iSelected = (int)MyDialog.DoModal();
\r
1178 if (iSelected >= 0) SelectPage(iSelected);
\r
1181 inline void CTab::SwapTabs(UINT nTab1, UINT nTab2)
\r
1183 if ((nTab1 < GetAllTabs().size()) && (nTab2 < GetAllTabs().size()) && (nTab1 != nTab2))
\r
1185 int nPage = GetCurSel();
\r
1186 TabPageInfo T1 = GetTabPageInfo(nTab1);
\r
1187 TabPageInfo T2 = GetTabPageInfo(nTab2);
\r
1189 std::vector<TCHAR> vTChar1( nLength+1, _T('\0') ); // vector for TCHAR array
\r
1190 std::vector<TCHAR> vTChar2( nLength+1, _T('\0') ); // vector for TCHAR array
\r
1192 TCITEM Item1 = {0};
\r
1193 Item1.mask = TCIF_IMAGE | TCIF_PARAM | TCIF_RTLREADING | TCIF_STATE | TCIF_TEXT;
\r
1194 Item1.cchTextMax = nLength;
\r
1195 Item1.pszText = &vTChar1.front();
\r
1196 GetItem(nTab1, &Item1);
\r
1198 TCITEM Item2 = {0};
\r
1199 Item2.mask = TCIF_IMAGE | TCIF_PARAM | TCIF_RTLREADING | TCIF_STATE | TCIF_TEXT;
\r
1200 Item2.cchTextMax = nLength;
\r
1201 Item2.pszText = &vTChar2.front();
\r
1202 GetItem(nTab2, &Item2);
\r
1204 TabCtrl_SetItem(m_hWnd, nTab1, &Item2);
\r
1205 TabCtrl_SetItem(m_hWnd, nTab2, &Item1);
\r
1206 m_vTabPageInfo[nTab1] = T2;
\r
1207 m_vTabPageInfo[nTab2] = T1;
\r
1208 SelectPage(nPage);
\r
1212 inline LRESULT CTab::WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam)
\r
1217 // Required for Windows NT
\r
1219 for (int i = GetItemCount()-1; i >= 0; --i)
\r
1226 if (GetWindowLongPtr(GWL_STYLE) & TCS_OWNERDRAWFIXED)
\r
1228 // Remove all pending paint requests
\r
1230 ::BeginPaint(m_hWnd, &ps);
\r
1231 ::EndPaint(m_hWnd, &ps);
\r
1233 // Now call our local Paint
\r
1238 case WM_ERASEBKGND:
\r
1239 if (GetWindowLongPtr(GWL_STYLE) & TCS_OWNERDRAWFIXED)
\r
1242 case WM_KILLFOCUS:
\r
1243 m_IsClosePressed = FALSE;
\r
1245 case WM_LBUTTONDBLCLK:
\r
1246 case WM_LBUTTONDOWN:
\r
1247 OnLButtonDown(wParam, lParam);
\r
1249 case WM_LBUTTONUP:
\r
1250 OnLButtonUp(wParam, lParam);
\r
1252 case WM_MOUSEMOVE:
\r
1253 OnMouseMove(wParam, lParam);
\r
1255 case WM_MOUSELEAVE:
\r
1256 OnMouseLeave(wParam, lParam);
\r
1258 case WM_NCHITTEST:
\r
1259 return OnNCHitTest(wParam, lParam);
\r
1261 case WM_WINDOWPOSCHANGING:
\r
1262 // A little hack to reduce tab flicker
\r
1263 if (IsWindowVisible() && (GetWindowLongPtr(GWL_STYLE) & TCS_OWNERDRAWFIXED))
\r
1265 LPWINDOWPOS pWinPos = (LPWINDOWPOS)lParam;
\r
1266 pWinPos->flags |= SWP_NOREDRAW;
\r
1271 case WM_WINDOWPOSCHANGED:
\r
1276 // pass unhandled messages on for default processing
\r
1277 return CWnd::WndProcDefault(uMsg, wParam, lParam);
\r
1280 // Wrappers for Win32 Macros
\r
1281 inline void CTab::AdjustRect(BOOL fLarger, RECT *prc) const
\r
1283 assert(::IsWindow(m_hWnd));
\r
1284 TabCtrl_AdjustRect(m_hWnd, fLarger, prc);
\r
1287 inline int CTab::GetCurFocus() const
\r
1289 assert(::IsWindow(m_hWnd));
\r
1290 return TabCtrl_GetCurFocus(m_hWnd);
\r
1293 inline int CTab::GetCurSel() const
\r
1295 assert(::IsWindow(m_hWnd));
\r
1296 return TabCtrl_GetCurSel(m_hWnd);
\r
1299 inline BOOL CTab::GetItem(int iItem, LPTCITEM pitem) const
\r
1301 assert(::IsWindow(m_hWnd));
\r
1302 return TabCtrl_GetItem(m_hWnd, iItem, pitem);
\r
1305 inline int CTab::GetItemCount() const
\r
1307 assert(::IsWindow(m_hWnd));
\r
1308 return TabCtrl_GetItemCount(m_hWnd);
\r
1311 inline int CTab::HitTest(TCHITTESTINFO& info) const
\r
1313 assert(::IsWindow(m_hWnd));
\r
1314 return TabCtrl_HitTest(m_hWnd, &info);
\r
1317 inline void CTab::SetCurFocus(int iItem) const
\r
1319 assert(::IsWindow(m_hWnd));
\r
1320 TabCtrl_SetCurFocus(m_hWnd, iItem);
\r
1323 inline int CTab::SetCurSel(int iItem) const
\r
1325 assert(::IsWindow(m_hWnd));
\r
1326 return TabCtrl_SetCurSel(m_hWnd, iItem);
\r
1329 inline DWORD CTab::SetItemSize(int cx, int cy) const
\r
1331 assert(::IsWindow(m_hWnd));
\r
1332 return TabCtrl_SetItemSize(m_hWnd, cx, cy);
\r
1335 inline int CTab::SetMinTabWidth(int cx) const
\r
1337 assert(::IsWindow(m_hWnd));
\r
1338 return TabCtrl_SetMinTabWidth(m_hWnd, cx);
\r
1341 inline void CTab::SetPadding(int cx, int cy) const
\r
1343 assert(::IsWindow(m_hWnd));
\r
1344 TabCtrl_SetPadding(m_hWnd, cx, cy);
\r
1347 ////////////////////////////////////////
\r
1348 // Definitions for the CTabbedMDI class
\r
1349 inline CTabbedMDI::CTabbedMDI()
\r
1351 GetTab().SetShowButtons(TRUE);
\r
1354 inline CTabbedMDI::~CTabbedMDI()
\r
1358 inline CWnd* CTabbedMDI::AddMDIChild(CWnd* pView, LPCTSTR szTabText, int idMDIChild /*= 0*/)
\r
1361 assert(lstrlen(szTabText) < MAX_MENU_STRING);
\r
1363 GetTab().AddTabPage(WndPtr(pView), szTabText, 0, idMDIChild);
\r
1365 // Fake a WM_MOUSEACTIVATE to propogate focus change to dockers
\r
1367 GetParent()->SendMessage(WM_MOUSEACTIVATE, (WPARAM)GetAncestor(), MAKELPARAM(HTCLIENT,WM_LBUTTONDOWN));
\r
1372 inline void CTabbedMDI::CloseActiveMDI()
\r
1374 int nTab = GetTab().GetCurSel();
\r
1376 GetTab().RemoveTabPage(nTab);
\r
1381 inline void CTabbedMDI::CloseAllMDIChildren()
\r
1383 while (GetMDIChildCount() > 0)
\r
1385 GetTab().RemoveTabPage(0);
\r
1389 inline void CTabbedMDI::CloseMDIChild(int nTab)
\r
1391 GetTab().RemoveTabPage(nTab);
\r
1393 if (GetActiveMDIChild())
\r
1394 GetActiveMDIChild()->RedrawWindow();
\r
1397 inline HWND CTabbedMDI::Create(CWnd* pParent /* = NULL*/)
\r
1399 CLIENTCREATESTRUCT clientcreate ;
\r
1400 clientcreate.hWindowMenu = m_hWnd;
\r
1401 clientcreate.idFirstChild = IDW_FIRSTCHILD ;
\r
1402 DWORD dwStyle = WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES;
\r
1404 // Create the MDICLIENT view window
\r
1405 if (!CreateEx(0, _T("MDICLIENT"), _T(""),
\r
1406 dwStyle, 0, 0, 0, 0, pParent, NULL, (PSTR) &clientcreate))
\r
1407 throw CWinException(_T("CMDIClient::Create ... CreateEx failed"));
\r
1412 inline CWnd* CTabbedMDI::GetActiveMDIChild() const
\r
1414 CWnd* pView = NULL;
\r
1415 int nTab = GetTab().GetCurSel();
\r
1418 TabPageInfo tbi = GetTab().GetTabPageInfo(nTab);
\r
1419 pView = tbi.pView;
\r
1425 inline int CTabbedMDI::GetActiveMDITab() const
\r
1427 return GetTab().GetCurSel();
\r
1430 inline CWnd* CTabbedMDI::GetMDIChild(int nTab) const
\r
1432 assert(nTab >= 0);
\r
1433 assert(nTab < GetMDIChildCount());
\r
1434 return GetTab().GetTabPageInfo(nTab).pView;
\r
1437 inline int CTabbedMDI::GetMDIChildCount() const
\r
1439 return (int) GetTab().GetAllTabs().size();
\r
1442 inline int CTabbedMDI::GetMDIChildID(int nTab) const
\r
1444 assert(nTab >= 0);
\r
1445 assert(nTab < GetMDIChildCount());
\r
1446 return GetTab().GetTabPageInfo(nTab).idTab;
\r
1449 inline LPCTSTR CTabbedMDI::GetMDIChildTitle(int nTab) const
\r
1451 assert(nTab >= 0);
\r
1452 assert(nTab < GetMDIChildCount());
\r
1453 return GetTab().GetTabPageInfo(nTab).szTabText;
\r
1456 inline BOOL CTabbedMDI::LoadRegistrySettings(CString strRegistryKeyName)
\r
1458 BOOL bResult = FALSE;
\r
1460 if (!strRegistryKeyName.IsEmpty())
\r
1462 CString strKey = _T("Software\\") + strRegistryKeyName + _T("\\MDI Children");
\r
1464 RegOpenKeyEx(HKEY_CURRENT_USER, strKey, 0, KEY_READ, &hKey);
\r
1467 DWORD dwType = REG_BINARY;
\r
1468 DWORD BufferSize = sizeof(TabPageInfo);
\r
1469 TabPageInfo tbi = {0};
\r
1471 TCHAR szNumber[16];
\r
1472 CString strSubKey = _T("MDI Child ");
\r
1473 strSubKey += _itot(i, szNumber, 10);
\r
1475 // Fill the DockList vector from the registry
\r
1476 while (0 == RegQueryValueEx(hKey, strSubKey, NULL, &dwType, (LPBYTE)&tbi, &BufferSize))
\r
1478 CWnd* pWnd = NewMDIChildFromID(tbi.idTab);
\r
1481 AddMDIChild(pWnd, tbi.szTabText, tbi.idTab);
\r
1483 strSubKey = _T("MDI Child ");
\r
1484 strSubKey += _itot(i, szNumber, 10);
\r
1489 TRACE(_T("Failed to get TabbedMDI info from registry"));
\r
1495 // Load Active MDI Tab from the registry
\r
1496 strSubKey = _T("Active MDI Tab");
\r
1498 dwType = REG_DWORD;
\r
1499 BufferSize = sizeof(int);
\r
1500 if(ERROR_SUCCESS == RegQueryValueEx(hKey, strSubKey, NULL, &dwType, (LPBYTE)&nTab, &BufferSize))
\r
1501 SetActiveMDITab(nTab);
\r
1503 SetActiveMDITab(0);
\r
1505 RegCloseKey(hKey);
\r
1510 CloseAllMDIChildren();
\r
1515 inline CWnd* CTabbedMDI::NewMDIChildFromID(int /*idMDIChild*/)
\r
1517 // Override this function to create new MDI children from IDs as shown below
\r
1518 CWnd* pView = NULL;
\r
1522 pView = new CViewSimple;
\r
1525 pView = new CViewRect;
\r
1528 TRACE(_T("Unknown MDI child ID\n"));
\r
1535 inline void CTabbedMDI::OnCreate()
\r
1537 GetTab().Create(this);
\r
1538 GetTab().SetFixedWidth(TRUE);
\r
1539 GetTab().SetOwnerDraw(TRUE);
\r
1542 inline void CTabbedMDI::OnDestroy(WPARAM /*wParam*/, LPARAM /*lParam*/ )
\r
1544 CloseAllMDIChildren();
\r
1547 inline LRESULT CTabbedMDI::OnNotify(WPARAM /*wParam*/, LPARAM lParam)
\r
1549 LPNMHDR pnmhdr = (LPNMHDR)lParam;
\r
1550 if (pnmhdr->code == UWM_TAB_CHANGED)
\r
1556 inline void CTabbedMDI::OnWindowPosChanged(WPARAM /*wParam*/, LPARAM /*lParam*/)
\r
1561 inline void CTabbedMDI::RecalcLayout()
\r
1563 if (GetTab().IsWindow())
\r
1565 if (GetTab().GetItemCount() >0)
\r
1567 CRect rcClient = GetClientRect();
\r
1568 GetTab().SetWindowPos(NULL, rcClient, SWP_SHOWWINDOW);
\r
1569 GetTab().UpdateWindow();
\r
1573 CRect rcClient = GetClientRect();
\r
1574 GetTab().SetWindowPos(NULL, rcClient, SWP_HIDEWINDOW);
\r
1580 inline BOOL CTabbedMDI::SaveRegistrySettings(CString strRegistryKeyName)
\r
1582 if (!strRegistryKeyName.IsEmpty())
\r
1584 CString strKeyName = _T("Software\\") + strRegistryKeyName;
\r
1586 HKEY hKeyMDIChild = NULL;
\r
1590 if (ERROR_SUCCESS != RegCreateKeyEx(HKEY_CURRENT_USER, strKeyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL))
\r
1591 throw (CWinException(_T("RegCreateKeyEx Failed")));
\r
1593 RegDeleteKey(hKey, _T("MDI Children"));
\r
1594 if (ERROR_SUCCESS != RegCreateKeyEx(hKey, _T("MDI Children"), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKeyMDIChild, NULL))
\r
1595 throw (CWinException(_T("RegCreateKeyEx Failed")));
\r
1597 for (int i = 0; i < GetMDIChildCount(); ++i)
\r
1599 TCHAR szNumber[16];
\r
1600 CString strSubKey = _T("MDI Child ");
\r
1601 strSubKey += _itot(i, szNumber, 10);
\r
1602 TabPageInfo pdi = GetTab().GetTabPageInfo(i);
\r
1603 if (ERROR_SUCCESS != RegSetValueEx(hKeyMDIChild, strSubKey, 0, REG_BINARY, (LPBYTE)&pdi, sizeof(TabPageInfo)))
\r
1604 throw (CWinException(_T("RegSetValueEx Failed")));
\r
1607 // Add Active Tab to the registry
\r
1608 CString strSubKey = _T("Active MDI Tab");
\r
1609 int nTab = GetActiveMDITab();
\r
1610 if(ERROR_SUCCESS != RegSetValueEx(hKeyMDIChild, strSubKey, 0, REG_DWORD, (LPBYTE)&nTab, sizeof(int)))
\r
1611 throw (CWinException(_T("RegSetValueEx failed")));
\r
1613 RegCloseKey(hKeyMDIChild);
\r
1614 RegCloseKey(hKey);
\r
1616 catch (const CWinException& e)
\r
1618 // Roll back the registry changes by deleting the subkeys
\r
1623 RegDeleteKey(hKeyMDIChild, _T("MDI Children"));
\r
1624 RegCloseKey(hKeyMDIChild);
\r
1627 RegDeleteKey(HKEY_CURRENT_USER, strKeyName);
\r
1628 RegCloseKey(hKey);
\r
1639 inline void CTabbedMDI::SetActiveMDIChild(CWnd* pWnd)
\r
1642 int nPage = GetTab().GetTabIndex(pWnd);
\r
1644 GetTab().SelectPage(nPage);
\r
1647 inline void CTabbedMDI::SetActiveMDITab(int iTab)
\r
1649 assert(::IsWindow(m_hWnd));
\r
1650 assert(GetTab().IsWindow());
\r
1651 GetTab().SelectPage(iTab);
\r
1654 inline LRESULT CTabbedMDI::WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam)
\r
1659 OnDestroy(wParam, lParam);
\r
1662 case WM_WINDOWPOSCHANGED:
\r
1663 OnWindowPosChanged(wParam, lParam);
\r
1667 return CWnd::WndProcDefault(uMsg, wParam, lParam);
\r
1670 } // namespace Win32xx
\r
1672 #endif // _WIN32XX_TAB_H_
\r