📄 customtabctrl.cpp
字号:
#include "CustomTabCtrl.h"
//////////////////////////////////////////////////////////////////////////
CCustomTabItem::CCustomTabItem(CString sText, LPARAM lParam) :
m_sText(sText),
m_lParam(lParam),
m_bShape(TAB_INVISIBLE),
m_fSelected(FALSE),
m_fHighlighted(FALSE),
m_fHighlightChanged(FALSE)
{
}
//////////////////////////////////////////////////////////////////////////
void CCustomTabItem::operator=(const CCustomTabItem &other)
{
m_sText = other.m_sText;
m_lParam = other.m_lParam;
}
//////////////////////////////////////////////////////////////////////////
void CCustomTabItem::Draw(CDC& dc, CFont& font, TabItemColors *pColors, BOOL fOnTop, BOOL fNoLines)
{
COLORREF bgColor, fgColor;
if(m_fSelected || m_fHighlighted)
{
bgColor=pColors->crBkgActive;
fgColor=pColors->crTxtActive;
}
else
{
bgColor=pColors->crBkgInactive;
fgColor=pColors->crTxtInactive;
}
CBrush brush(bgColor);
CPen blackPen(PS_SOLID, 1, pColors->crDarkLine);
CPen shadowPen(PS_SOLID, 1, pColors->crLightLine);
CRect rc = m_rect;
// Paint item background
dc.FillRect(&m_rect, &brush);
CPen* pOldPen = dc.SelectObject(&blackPen);
if(!fNoLines)
{
if(fOnTop)
{
dc.MoveTo(rc.left, rc.bottom);
dc.LineTo(rc.left, rc.top);
dc.LineTo(rc.right, rc.top);
dc.LineTo(rc.right, rc.bottom);
}
else
{
dc.MoveTo(rc.left, rc.top);
dc.LineTo(rc.left, rc.bottom-1);
dc.LineTo(rc.right, rc.bottom-1);
dc.LineTo(rc.right, rc.top);
}
}
// draw item text
COLORREF bgOldColor = dc.SetBkColor(bgColor);
COLORREF fgOldColor = dc.SetTextColor(fgColor);
rc.DeflateRect(rc.Height()/2, 2, rc.Height()/2, 2);
CFont* pOldFont = dc.SelectObject(&font);
dc.DrawText(m_sText, &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
dc.SelectObject(pOldFont);
dc.SetTextColor(fgOldColor);
dc.SetBkColor(bgOldColor);
dc.SelectObject(pOldPen);
}
//////////////////////////////////////////////////////////////////////////
#ifdef _WIN32_WCE
LOGFONT CCustomTabCtrl::lf_default = {12, 0, 0, 0, FW_NORMAL, 0, 0, 0,
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_CHARACTER_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, _T("Tahoma") };
LOGFONT CCustomTabCtrl::lf_default_vga = {24, 0, 0, 0, FW_NORMAL, 0, 0, 0,
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_CHARACTER_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, _T("Tahoma") };
#else
LOGFONT CCustomTabCtrl::lf_default = {12, 0, 0, 0, FW_NORMAL, 0, 0, 0,
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_CHARACTER_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, _T("Microsoft Sans Serif") };
#endif
BYTE CCustomTabCtrl::m_bBitsGlyphs[] = {
0xBD,0xFB,0xDF,0xBD,0x3C,0x00,
0xB9,0xF3,0xCF,0x9D,0x99,0x00,
0xB1,0xE3,0xC7,0x8D,0xC3,0x00,
0xA3,0xC7,0xE3,0xC5,0xE7,0x00,
0xB1,0xE3,0xC7,0x8D,0xC3,0x00,
0xB9,0xF3,0xCF,0x9D,0x99,0x00,
0xBD,0xFB,0xDF,0xBD,0x3C,0x00
};
IMPLEMENT_DYNAMIC(CCustomTabCtrl, CWnd)
//////////////////////////////////////////////////////////////////////////
CCustomTabCtrl::CCustomTabCtrl() :
m_nButtonIDDown(CTCID_NOBUTTON),
m_nPrevState(BNST_INVISIBLE),
m_nNextState(BNST_INVISIBLE),
m_nFirstState(BNST_INVISIBLE),
m_nLastState(BNST_INVISIBLE),
m_nCloseState(BNST_INVISIBLE),
m_nItemSelected(-1),
m_nFirstVisibleItem(0),
m_dwLastRepeatTime(0),
m_nItemDragDest(0)
{
RegisterWindowClass();
m_bmpGlyphsMono.CreateBitmap(48, 7, 1, 1, m_bBitsGlyphs);
//initialize tab/tabitem colors
m_ticColors.crBkgInactive=GetSysColor(COLOR_3DFACE);
m_ticColors.crBkgActive=GetSysColor(COLOR_WINDOW);
m_ticColors.crTxtInactive=GetSysColor(COLOR_BTNTEXT);
m_ticColors.crTxtActive=GetSysColor(COLOR_WINDOWTEXT);
m_ticColors.crDarkLine=GetSysColor(COLOR_BTNTEXT);
m_ticColors.crLightLine=GetSysColor(COLOR_3DSHADOW);
m_ticColors.crWndBkg=GetSysColor(COLOR_WINDOW);
if(GetSystemMetrics(SM_CYSCREEN) > 320 || GetSystemMetrics(SM_CXSCREEN) > 320)
{
//vga device?
m_nTabsHeight=50;
SetControlFont(lf_default_vga);
}
else
{
m_nTabsHeight=25;
SetControlFont(lf_default);
}
}
// Register the window class if it has not already been registered.
//////////////////////////////////////////////////////////////////////////
BOOL CCustomTabCtrl::RegisterWindowClass()
{
WNDCLASS wndcls;
HINSTANCE hInst;
hInst = AfxGetInstanceHandle();
if(!(::GetClassInfo(hInst, CustomTabCtrl_CLASSNAME, &wndcls)))
{
wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wndcls.lpfnWndProc = ::DefWindowProc;
wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
wndcls.hInstance = hInst;
wndcls.hIcon = NULL;
wndcls.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
wndcls.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1);
wndcls.lpszMenuName = NULL;
wndcls.lpszClassName = CustomTabCtrl_CLASSNAME;
if(!AfxRegisterClass(&wndcls))
{
AfxThrowResourceException();
return FALSE;
}
}
return TRUE;
}
//////////////////////////////////////////////////////////////////////////
CCustomTabCtrl::~CCustomTabCtrl()
{
int i;
for(i=0; i< m_aItems.GetSize(); i++)
{
delete m_aItems[i];
}
m_aItems.RemoveAll();
}
BEGIN_MESSAGE_MAP(CCustomTabCtrl, CWnd)
//{{AFX_MSG_MAP(CCustomTabCtrl)
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_PAINT()
ON_WM_ERASEBKGND()
ON_WM_SIZE()
ON_WM_LBUTTONDBLCLK()
ON_WM_TIMER()
ON_EN_UPDATE(CTCID_EDITCTRL, OnUpdateEdit)
#ifndef _WIN32_WCE
ON_WM_RBUTTONDBLCLK()
ON_WM_RBUTTONDOWN()
#endif
ON_MESSAGE(TCM_ADJUSTRECT, OnTcmAdjustRect)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
//////////////////////////////////////////////////////////////////////////
void CCustomTabCtrl::AdjustRect(BOOL bLarger, LPRECT lpRect)
{
if(IsWindow(m_hWnd))
{
::SendMessage(m_hWnd, TCM_ADJUSTRECT, bLarger, (LPARAM)lpRect);
}
}
//////////////////////////////////////////////////////////////////////////
LRESULT CCustomTabCtrl::OnTcmAdjustRect(WPARAM wParam, LPARAM lParam)
{
LPRECT pRect;
pRect=(LPRECT)lParam;
if(pRect == NULL)
{
return 0;
}
if(IsContainer())
{
if(wParam)
{
//return entire window rect
GetWindowRect(pRect);
}
else
{
if(GetStyle() & CTCS_TOP)
{
pRect->top = m_nTabsHeight;
}
else
{
pRect->bottom -= m_nTabsHeight;
}
}
}
else
{
//not a container, AdjustRect not supported
}
return 0;
}
//////////////////////////////////////////////////////////////////////////
//get tabs height (makes sense if has container style)
int CCustomTabCtrl::GetTabsHeight()
{
CRect rc;
if(IsContainer())
{
return m_nTabsHeight;
}
else
{
GetClientRect(&rc);
if(IsVertical())
{
return rc.Width();
}
else
{
return rc.Height();
}
}
}
//////////////////////////////////////////////////////////////////////////
//set tabs height (makes sense if has container style)
void CCustomTabCtrl::SetTabsHeight(int nHeight)
{
m_nTabsHeight=nHeight;
RecalcLayout(RECALC_RESIZED, m_nItemSelected);
}
//////////////////////////////////////////////////////////////////////////
//set control colors, and optionally redraw.
void CCustomTabCtrl::SetColors(TabItemColors *pColorsIn, BOOL fRedraw)
{
if(pColorsIn != NULL)
{
m_ticColors.crBkgActive = pColorsIn->crBkgActive;
m_ticColors.crBkgInactive = pColorsIn->crBkgInactive;
m_ticColors.crDarkLine = pColorsIn->crDarkLine;
m_ticColors.crLightLine = pColorsIn->crLightLine;
m_ticColors.crTxtActive = pColorsIn->crTxtActive;
m_ticColors.crTxtInactive = pColorsIn->crTxtInactive;
m_ticColors.crWndBkg = pColorsIn->crWndBkg;
}
if(fRedraw)
{
Invalidate(FALSE);
}
}
//////////////////////////////////////////////////////////////////////////
//return RECT where tabs are: the entire window rect if not a container, tabs only otherwise.
void CCustomTabCtrl::GetTabsRect(LPRECT pRect)
{
CRect rc;
if(pRect == NULL)
{
return;
}
GetClientRect(&rc);
if(IsContainer())
{
if(GetStyle() & CTCS_TOP)
{
rc.bottom=rc.top + m_nTabsHeight;
}
else
{
rc.top=rc.bottom - m_nTabsHeight;
}
}
*pRect = rc;
}
//////////////////////////////////////////////////////////////////////////
//get control colors
void CCustomTabCtrl::GetColors(TabItemColors *pColorsOut)
{
if(pColorsOut != NULL)
{
pColorsOut->crBkgActive = m_ticColors.crBkgActive;
pColorsOut->crBkgInactive = m_ticColors.crBkgInactive;
pColorsOut->crDarkLine = m_ticColors.crDarkLine;
pColorsOut->crLightLine = m_ticColors.crLightLine;
pColorsOut->crTxtActive = m_ticColors.crTxtActive;
pColorsOut->crTxtInactive = m_ticColors.crTxtInactive;
pColorsOut->crWndBkg = m_ticColors.crWndBkg;
}
}
//////////////////////////////////////////////////////////////////////////
BOOL CCustomTabCtrl::Create(UINT dwStyle, const CRect & rect, CWnd * pParentWnd, UINT nID)
{
return CWnd::Create(CustomTabCtrl_CLASSNAME, _T(""), dwStyle, rect, pParentWnd, nID);
}
//////////////////////////////////////////////////////////////////////////
BOOL CCustomTabCtrl::OnEraseBkgnd(CDC* pDC)
{
return TRUE;
}
//////////////////////////////////////////////////////////////////////////
void CCustomTabCtrl::OnPaint()
{
int i, nBtns;
CRect rCl, rWnd;
CDC dcMem;
CBitmap bmpMem;
CPaintDC dc(this);
{
m_rgbGlyph[0] = GetSysColor(COLOR_BTNTEXT);
m_rgbGlyph[1] = GetSysColor(COLOR_BTNTEXT);
m_rgbGlyph[2] = GetSysColor(COLOR_BTNTEXT);
m_rgbGlyph[3] = GetSysColor(COLOR_BTNTEXT);
}
GetTabsRect(&rCl);
GetClientRect(&rWnd);
if(IsVertical())
{
rCl.SetRect(0, 0, rCl.Height(), rCl.Width());
}
CPen blackPen(PS_SOLID, 1, m_ticColors.crDarkLine);
CBitmap* pOldBmp=NULL;
if(dcMem.CreateCompatibleDC(&dc))
{
if(bmpMem.CreateCompatibleBitmap(&dc, rWnd.Width(), rWnd.Height()))
{
pOldBmp = dcMem.SelectObject(&bmpMem);
}
else
{
return;
}
}
else
{
return;
}
// clear background
dcMem.FillSolidRect(&rCl, m_ticColors.crWndBkg);
nBtns = 0;
if(m_nCloseState)
{
nBtns++;
}
if(m_nPrevState)
{
nBtns += 2;
}
if(m_nFirstState)
{
nBtns += 2;
}
BOOL fAfter = (BOOL)GetStyle()&CTCS_BUTTONSAFTER;
BOOL fTop = (BOOL)GetStyle()&CTCS_TOP;
int nA = rCl.Height()-2;
CRect rAll;
if(fTop)
{
rAll.SetRect(0, 0, nBtns*nA+3, rCl.Height()-1);
}
else
{
rAll.SetRect(0, rCl.top, nBtns*nA+3, rCl.bottom);
}
if(nBtns == 0)
{
rAll.SetRectEmpty();
}
int nCloseOffset = 0;
if(fAfter)
{
nCloseOffset = rCl.Width() - rAll.Width();
rAll.OffsetRect(nCloseOffset, 0);
}
// draw tab items visible and not selected
for(i=0; i<m_aItems.GetSize(); i++)
{
if(m_aItems[i]->m_bShape && !m_aItems[i]->m_fSelected)
{
if(m_aItems[i]->m_fHighlighted)
{
m_aItems[i]->Draw(dcMem, m_FontSelected, &m_ticColors, GetStyle()&CTCS_TOP, GetStyle()&CTCS_NOLINES);
}
else
{
m_aItems[i]->Draw(dcMem, m_Font, &m_ticColors, GetStyle()&CTCS_TOP, GetStyle()&CTCS_NOLINES);
}
}
}
// draw selected tab item
if(m_nItemSelected!=-1 && m_aItems[m_nItemSelected]->m_bShape)
{
m_aItems[m_nItemSelected]->Draw(dcMem, m_FontSelected, &m_ticColors, GetStyle()&CTCS_TOP, GetStyle()&CTCS_NOLINES);
}
if(m_nCloseState || m_nPrevState)
{
CPen* pOldPen = dcMem.SelectObject(&blackPen);
dcMem.Rectangle(rAll);
dcMem.SelectObject(pOldPen);
}
// draw buttons
if(m_nCloseState)
{
BOOL fMirrored = TRUE;
if(!fAfter)
{
fMirrored = FALSE;
}
CRect rClose;
if(fAfter)
{
if(fTop)
{
rClose.SetRect(rCl.Width()-nA-2, 1, rCl.Width()-1, rCl.Height());
}
else
{
rClose.SetRect(rCl.Width()-nA-2, rCl.top, rCl.Width()-1, rCl.bottom-1);
}
}
else
{
nCloseOffset = nA;
if(fTop)
{
rClose.SetRect(1, 1, nA+1, rCl.Height());
}
else
{
rClose.SetRect(1, rCl.top, nA+1, rCl.bottom-1);
}
}
CPoint ptClose(rClose.left + (rClose.Width()-8)/2 + rClose.Width()%2, rClose.top + (rClose.Height()-7)/2);
/*
if(fMirrored && m_hBmpBkRightSpin)
{
DrawBk(dcMem, rClose, m_hBmpBkRightSpin, m_fIsRightImageHorLayout, m_mrgnRight, m_nCloseState-1);
}
else if(m_hBmpBkLeftSpin)
{
DrawBk(dcMem, rClose, m_hBmpBkLeftSpin, m_fIsLeftImageHorLayout, m_mrgnLeft, m_nCloseState-1);
}
else
*/
{
if(m_nCloseState == BNST_PRESSED)
{
dcMem.DrawFrameControl(rClose, DFC_BUTTON, DFCS_BUTTONPUSH|DFCS_PUSHED);
}
else
{
dcMem.DrawFrameControl(rClose, DFC_BUTTON, DFCS_BUTTONPUSH);
}
}
DrawGlyph(dcMem, ptClose, 4, m_nCloseState-1);
}
if(m_nPrevState)
{
CRect rFirst, rPrev, rNext, rLast;
if(fTop)
{
if(nBtns<4)
{
rPrev.SetRect(nCloseOffset+1, 1, nCloseOffset+nA+1, rCl.Height());
rNext.SetRect(nCloseOffset+nA+2, 1, nCloseOffset+2*nA+2, rCl.Height());
}
else
{
rFirst.SetRect(nCloseOffset+1, 1, nCloseOffset+nA+1, rCl.Height());
rPrev.SetRect(nCloseOffset+nA+1, 1, nCloseOffset+2*nA+1, rCl.Height());
rNext.SetRect(nCloseOffset+2*nA+2, 1, nCloseOffset+3*nA+2, rCl.Height());
rLast.SetRect(nCloseOffset+3*nA+2, 1, nCloseOffset+4*nA+2, rCl.Height());
}
}
else
{
if(nBtns<4)
{
rPrev.SetRect(nCloseOffset+1, rCl.top, nCloseOffset+nA+1, rCl.bottom);
rNext.SetRect(nCloseOffset+nA+2, rCl.top, nCloseOffset+2*nA+2, rCl.bottom);
}
else
{
rFirst.SetRect(nCloseOffset+1, rCl.top, nCloseOffset+nA+1, rCl.bottom);
rPrev.SetRect(nCloseOffset+nA+1, rCl.top, nCloseOffset+2*nA+1, rCl.bottom);
rNext.SetRect(nCloseOffset+2*nA+2, rCl.top, nCloseOffset+3*nA+2, rCl.bottom);
rLast.SetRect(nCloseOffset+3*nA+2, rCl.top, nCloseOffset+4*nA+2, rCl.bottom);
}
}
if(nBtns>=4)
{
CPoint ptFirst(rFirst.left + (rFirst.Width()-8)/2, rFirst.top + (rFirst.Height()-7)/2);
/*
if(m_hBmpBkLeftSpin)
{
DrawBk(dcMem, rFirst, m_hBmpBkLeftSpin, m_fIsLeftImageHorLayout, m_mrgnLeft, m_nFirstState-1);
}
else
*/
{
if(m_nFirstState == BNST_PRESSED)
{
dcMem.DrawFrameControl(rFirst, DFC_BUTTON, DFCS_BUTTONPUSH|DFCS_PUSHED);
}
else
{
dcMem.DrawFrameControl(rFirst, DFC_BUTTON, DFCS_BUTTONPUSH);
}
}
DrawGlyph(dcMem, ptFirst, 0, m_nFirstState-1);
CPoint ptLast(rLast.left + (rLast.Width()-8)/2, rLast.top+(rLast.Height()-7)/2);
/*
if(m_hBmpBkRightSpin)
{
DrawBk(dcMem, rLast, m_hBmpBkRightSpin, m_fIsRightImageHorLayout, m_mrgnRight, m_nLastState-1);
}
else
*/
{
if(m_nLastState == BNST_PRESSED)
{
dcMem.DrawFrameControl(rLast, DFC_BUTTON, DFCS_BUTTONPUSH|DFCS_PUSHED);
}
else
{
dcMem.DrawFrameControl(rLast, DFC_BUTTON, DFCS_BUTTONPUSH);
}
}
DrawGlyph(dcMem,ptLast, 3, m_nLastState-1);
}
CPoint ptPrev(rPrev.left + (rPrev.Width()-8)/2, rPrev.top+(rPrev.Height()-7)/2);
/*
if(m_hBmpBkLeftSpin)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -