📄 cooltabctrls.h
字号:
#ifndef __COOLTABCTRLS_H__
#define __COOLTABCTRLS_H__
#pragma once
/////////////////////////////////////////////////////////////////////////////
// CCoolTabCtrls - A set of Tab Controls with different appearances
//
// Written by Bjarke Viksoe (bjarke@viksoe.dk)
// Several improvements done by Daniel Bowen.
// Copyright (c) 2001-2003 Bjarke Viksoe.
//
// Add the following macro to the parent's message map:
// REFLECT_NOTIFICATIONS()
// CFolderTabCtrl code based on a Paul DiLascia MSJ 1999 article.
//
// This code may be used in compiled form in any way you desire. This
// file may be redistributed by any means PROVIDING it is
// not sold for profit without the authors written consent, and
// providing that this notice and the authors name is included.
//
// This file is provided "as is" with no expressed or implied warranty.
// The author accepts no liability if it causes any damage to you or your
// computer whatsoever. It's free, so don't hassle me about it.
//
// Beware of bugs.
//
#ifndef __cplusplus
#error WTL requires C++ compilation (use a .cpp suffix)
#endif
#ifndef __ATLAPP_H__
#error CoolTabCtrls.h requires atlapp.h to be included first
#endif
#ifndef __ATLCTRLS_H__
#error CoolTabCtrls.h requires atlctrls.h to be included first
#endif
#ifndef __ATLGDIX_H__
#error CoolTabCtrls.h requires atlgdix.h to be included first
#endif
#if (_WIN32_IE < 0x0400)
#error CoolTabCtrls.h requires _WIN32_IE >= 0x0400
#endif
// New tab notifications
#ifndef TCN_INITIALIZE
#define TCN_INITIALIZE TCN_FIRST-10
#define TCN_INSERTITEM TCN_FIRST-11
#define TCN_DELETEITEM TCN_FIRST-12
#endif // TCN_INITIALIZE
// New masks
#define TCIF_TEXTCOLOR 0x1000
#define TCIF_BKCOLOR 0x2000
#define TCIF_TOOLTIP 0x4000
#define TCIF_WIDTH 0x8000
// New tab states
#define TCIS_DISABLED 0x1000
#define TCIS_HIDDEN 0x2000
// Extended tab styles
#define TCS_EX_SCROLLBUTTONS 0x00000010 // Displays scroll-buttons when needed
#define TCS_EX_FLATSCROLL 0x00000020 // Scroll-buttons are shown as flat
#define TCS_EX_CLOSEBUTTON 0x00000040 // Displays close-button to close tabs
#define TCS_EX_SELHIGHLIGHT 0x00000080 // Highlight selected tab with special font
#define TCS_EX_COMPRESSLINE 0x00000100 // Compress tabs if larger than client area
// Layout structure for tab
typedef struct
{
int cxIndent; // Start indent
int cxButtonSpacing; // Gap between buttons
int cxPadding; // Padding between text and button
int cxMargin; // Gap between button and content
int cxSelMargin; // Additional gap for curr. sel. button
int cxImagePadding; // Gap between text and image
int cxOverlap; // Expand currently curr. sel. button
} TCMETRICS;
typedef struct tagCOOLTCITEM : TCITEM
{
int cx;
RECT rcSize;
COLORREF clrText;
COLORREF clrBkgnd;
LPTSTR pszTipText;
} COOLTCITEM;
template< class T, class TBase = CTabCtrl, class TWinTraits = CControlWinTraits >
class ATL_NO_VTABLE CCustomTabCtrl :
public CWindowImpl< T, TBase, TWinTraits >,
public COffscreenDrawRect< T >
{
public:
DECLARE_WND_CLASS(TBase::GetWndClassName())
CCustomTabCtrl() :
m_iCurSel(-1),
m_dwExtStyle(0UL),
m_hFont(NULL),
m_hSelFont(NULL),
m_nMinWidth(-1)
{
::ZeroMemory(&m_metrics, sizeof(TCMETRICS));
}
// Data members
int m_iCurSel;
TCMETRICS m_metrics;
CSimpleValArray< COOLTCITEM* > m_Items;
CWindow m_wndNotify;
CToolTipCtrl m_Tip;
CImageList m_ImageList;
DWORD m_dwExtStyle;
UINT m_idDlgCtrl;
HFONT m_hFont;
HFONT m_hSelFont;
int m_nMinWidth;
// Operations
BOOL SubclassWindow(HWND hWnd)
{
ATLASSERT(m_hWnd==NULL);
ATLASSERT(::IsWindow(hWnd));
BOOL bRet = CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd);
if( bRet ) _Init();
return bRet;
}
int InsertItem(int iItem, LPCTSTR pstrText, int iImage = -1)
{
TCITEM tci = { 0 };
tci.mask = TCIF_TEXT | TCIF_IMAGE;
tci.pszText = const_cast<LPTSTR>(pstrText);
tci.iImage = iImage;
return InsertItem(iItem, &tci);
}
int InsertItem(int iItem, const LPTCITEM pItem)
{
COOLTCITEM tci;
::ZeroMemory(&tci, sizeof(tci));
::CopyMemory(&tci, pItem, sizeof(TCITEM));
return InsertItem(iItem, &tci);
}
int InsertItem(int iItem, const COOLTCITEM* pItem)
{
ATLASSERT(::IsWindow(m_hWnd));
ATLASSERT(pItem);
ATLASSERT(iItem==m_Items.GetSize()); // We only support appending right now
if( iItem < 0 || iItem > m_Items.GetSize() ) iItem = m_Items.GetSize();
COOLTCITEM* pNewItem;
ATLTRY( pNewItem = new COOLTCITEM );
if( pNewItem == NULL ) return -1;
::ZeroMemory(pNewItem, sizeof(COOLTCITEM));
m_Items.Add(pNewItem);
int idx = m_Items.GetSize() - 1;
if( !SetItem(idx, pItem) ) return FALSE;
// Send notification
NMHDR nmh = { m_hWnd, m_idDlgCtrl, TCN_INSERTITEM };
m_wndNotify.SendMessage(WM_NOTIFY, nmh.idFrom, (LPARAM) &nmh);
// Select if first tab
if( m_Items.GetSize() == 1 ) SetCurSel(0);
_Repaint();
return idx;
}
BOOL DeleteAllItems()
{
ATLASSERT(::IsWindow(m_hWnd));
while( GetItemCount() > 0 ) DeleteItem(0); // Slooow!!!
return TRUE;
}
BOOL DeleteItem(int iItem)
{
ATLASSERT(::IsWindow(m_hWnd));
if( iItem < 0 || iItem >= m_Items.GetSize() ) return FALSE;
// If currently selected, select something else
if( iItem < m_iCurSel ) {
// The item being removed is before the current selection.
// We still want the same item to be selected, but
// the index needs to be adjusted to account for the missing item
m_iCurSel--;
}
else if( iItem == m_iCurSel ) {
SetCurSel( (m_Items.GetSize() > 1) ? 0 : -1 );
}
// Remove from structures
COOLTCITEM* pItem = m_Items[iItem];
m_Items.RemoveAt(iItem);
if( pItem->mask & TCIF_TEXT ) ATLTRY( delete [] pItem->pszText );
if( pItem->mask & TCIF_TOOLTIP ) ATLTRY( delete [] pItem->pszTipText );
ATLTRY( delete pItem );
// Send notification
NMHDR nmh = { m_hWnd, m_idDlgCtrl, TCN_DELETEITEM };
m_wndNotify.SendMessage(WM_NOTIFY, nmh.idFrom, (LPARAM) &nmh);
_Repaint();
return TRUE;
}
int SetItem(int iItem, const LPTCITEM pItem)
{
COOLTCITEM tci;
::ZeroMemory(&tci, sizeof(tci));
::CopyMemory(&tci, pItem, sizeof(TCITEM));
return SetItem(iItem, &tci);
}
BOOL SetItem(int iItem, const COOLTCITEM* pItem)
{
ATLASSERT(::IsWindow(m_hWnd));
ATLASSERT(!::IsBadReadPtr(pItem,sizeof(TCITEM)));
if( !_ValidateItem(iItem) ) return FALSE;
// Copy caller's data to the internal structure
COOLTCITEM* pDstItem = m_Items[iItem];
UINT mask = pItem->mask;
if( mask & TCIF_TEXT ) {
ATLASSERT(!::IsBadStringPtr(pItem->pszText,(UINT)-1));
if( pDstItem->mask & TCIF_TEXT ) ATLTRY( delete [] pDstItem->pszText );
ATLTRY( pDstItem->pszText = new TCHAR[ ::lstrlen(pItem->pszText) + 1 ] );
::lstrcpy(pDstItem->pszText, pItem->pszText);
}
if( mask & TCIF_TOOLTIP ) {
ATLASSERT(!::IsBadStringPtr(pItem->pszTipText,(UINT)-1));
if( pDstItem->mask & TCIF_TOOLTIP ) ATLTRY( delete [] pDstItem->pszTipText );
ATLTRY( pDstItem->pszTipText = new TCHAR[ ::lstrlen(pItem->pszTipText) + 1 ] );
::lstrcpy(pDstItem->pszTipText, pItem->pszTipText);
}
if( mask & TCIF_STATE ) pDstItem->dwState = pItem->dwState;
if( mask & TCIF_IMAGE ) pDstItem->iImage = pItem->iImage;
if( mask & TCIF_PARAM ) pDstItem->lParam = pItem->lParam;
if( mask & TCIF_WIDTH ) pDstItem->cx = pItem->cx;
if( mask & TCIF_TEXTCOLOR ) pDstItem->clrText = pItem->clrText;
if( mask & TCIF_BKCOLOR ) pDstItem->clrBkgnd = pItem->clrBkgnd;
pDstItem->mask |= mask;
_Repaint();
return TRUE;
}
BOOL GetItem(int iItem, LPTCITEM pItem) const
{
ATLASSERT((pItem->mask & (TCIF_WIDTH|TCIF_TOOLTIP|TCIF_TEXTCOLOR|TCIF_BKCOLOR))==0);
return GetItem(iItem, reinterpret_cast<COOLTCITEM*>(pItem));
}
BOOL GetItem(int iItem, COOLTCITEM* pItem) const
{
ATLASSERT(::IsWindow(m_hWnd));
ATLASSERT(!::IsBadWritePtr(pItem,sizeof(TCITEM)));
if( !_ValidateItem(iItem) ) return FALSE;
// Copy item data
COOLTCITEM* pSrcItem = m_Items[iItem];
const UINT mask = pItem->mask;
const UINT maskSrc = pSrcItem->mask;
pItem->mask = 0;
if( mask & TCIF_TEXT ) {
ATLASSERT(pItem->pszText);
pItem->mask |= (maskSrc & TCIF_TEXT);
::lstrcpyn( pItem->pszText, pSrcItem->pszText == NULL ? _T("") : pSrcItem->pszText, pItem->cchTextMax );
}
if( mask & TCIF_IMAGE ) {
pItem->mask |= (maskSrc & TCIF_IMAGE);
pItem->iImage = pSrcItem->iImage;
}
if( mask & TCIF_PARAM ) {
pItem->mask |= (maskSrc & TCIF_PARAM);
pItem->lParam = pSrcItem->lParam;
}
if( mask & TCIF_STATE ) {
pItem->mask |= (maskSrc & TCIF_STATE);
pItem->dwState = pSrcItem->dwState;
}
if( mask & TCIF_TEXTCOLOR ) {
pItem->mask |= (maskSrc & TCIF_TEXTCOLOR);
pItem->clrText = pSrcItem->clrText;
}
if( mask & TCIF_BKCOLOR ) {
pItem->mask |= (maskSrc & TCIF_BKCOLOR);
pItem->clrBkgnd = pSrcItem->clrBkgnd;
}
return 0;
}
int SetCurSel(int iItem)
{
ATLASSERT(::IsWindow(m_hWnd));
// Selecting same tab? Not worth it!
if( iItem == m_iCurSel ) return m_iCurSel;
if( iItem < -1 || iItem >= m_Items.GetSize() ) return m_iCurSel;
RECT rc = { 0 };
int iOldSel = m_iCurSel;
// Send notification
NMHDR nmh = { m_hWnd, m_idDlgCtrl, TCN_SELCHANGING };
if( m_wndNotify.SendMessage(WM_NOTIFY, nmh.idFrom, (LPARAM) &nmh) == TRUE ) return -1;
// Repaint old button area
GetItemRect(iItem, &rc); InvalidateRect(&rc);
GetItemRect(iOldSel, &rc); InvalidateRect(&rc);
// Change tab
m_iCurSel = iItem;
// Recalc new positions
T* pT = static_cast<T*>(this);
pT->UpdateLayout();
// Repaint whole tab
GetClientRect(&rc); InvalidateRect(&rc);
// Send notification
nmh.code = TCN_SELCHANGE;
m_wndNotify.SendMessage(WM_NOTIFY, nmh.idFrom, (LPARAM) &nmh);
return iOldSel;
}
int GetCurSel() const
{
ATLASSERT(::IsWindow(m_hWnd));
return m_iCurSel;
}
int GetItemCount() const
{
ATLASSERT(::IsWindow(m_hWnd));
return m_Items.GetSize();
}
void SetImageList(HIMAGELIST hImageList)
{
m_ImageList = hImageList;
}
CImageList GetImageList() const
{
return m_ImageList;
}
int HitTest(POINT pt) const
{
TCHITTESTINFO tchti = { 0 };
tchti.pt = pt;
return HitTest(&tchti);
}
int HitTest(LPTCHITTESTINFO pinfo) const
{
ATLASSERT(!::IsBadWritePtr(pinfo,sizeof(TCHITTESTINFO)));
for( int i = 0; i < m_Items.GetSize(); i++ ) {
if( ::PtInRect(&m_Items[i]->rcSize, pinfo->pt) ) {
pinfo->flags = TCHT_ONITEM;
return i;
}
}
return -1;
}
DWORD GetExtendedStyle() const
{
ATLASSERT(::IsWindow(m_hWnd));
return m_dwExtStyle;
}
DWORD SetExtendedStyle(DWORD dwExMask, DWORD dwExStyle)
{
ATLASSERT(::IsWindow(m_hWnd));
DWORD dwOldStyle = m_dwExtStyle;
m_dwExtStyle = (m_dwExtStyle & ~dwExMask) | dwExStyle;
_Repaint();
return dwOldStyle;
}
int GetRowCount() const
{
return 1;
}
CToolTipCtrl GetTooltips() const
{
return m_Tip;
}
void SetNotify(HWND hWnd)
{
ATLASSERT(::IsWindow(hWnd));
m_wndNotify = hWnd;
}
void SetMinTabWidth(int nWidth = -1)
{
m_nMinWidth = nWidth;
}
DWORD SetItemSize(int iItem, int cx, int cy)
{
ATLASSERT(::IsWindow(m_hWnd));
if( !_ValidateItem(iItem) ) return 0;
RECT rcOld = m_Items[iItem]->rcSize;
m_Items[iItem].cx = cx;
m_Items[iItem].mask |= TCIF_WIDTH;
_Repaint();
return MAKELONG(rcOld.right - rcOld.left, rcOld.bottom - rcOld.top);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -