📄 customtabctrl.cpp
字号:
if(IsVertical())
{
rCl.SetRect(0, 0, rCl.Height(), rCl.Width());
}
int rightAdjusment = 0;
if(GetStyle() & CTCS_BUTTONSAFTER)
{
rightAdjusment = nOffset;
nOffset = 0;
}
for(i = 0; i<m_aItems.GetSize(); i++)
{
if(i < m_nFirstVisibleItem-1)
{
m_aItems[i]->m_bShape = TAB_INVISIBLE;
//nOffset -= m_aItems[i]->m_rect.Width()-rCl.Height()/2;
nOffset -= m_aItems[i]->m_rect.Width();
m_aItems[i]->m_rectText.SetRectEmpty();
}
else if(i == m_nFirstVisibleItem-1)
{
int nBtns = 2;
if(GetStyle() & CTCS_FOURBUTTONS)
{
nBtns = 4;
}
if(GetStyle() & CTCS_CLOSEBUTTON)
{
nBtns++;
}
int nBnWidth = nBtns*(rCl.Height() - 3) + 3;
m_aItems[i]->m_bShape = TAB_BEFORE_FIRST_VISIBLE;
//nOffset -= m_aItems[i]->m_rect.Width()-rCl.Height()/2;
//no overlapping
nOffset -= m_aItems[i]->m_rect.Width();
//overlap here
m_aItems[i]->m_rect.SetRect(0, 1, rCl.Height()/2, rCl.Height()-1);
if(!(GetStyle() & CTCS_BUTTONSAFTER))
{
m_aItems[i]->m_rect.OffsetRect(nBnWidth, 0);
}
//this prevents some overlapping in case of no BUTTONSAFTER style
m_aItems[i]->m_rect.SetRectEmpty();
//text rect empty anyways
m_aItems[i]->m_rectText.SetRectEmpty();
}
else
{
m_aItems[i]->m_bShape = TAB_VISIBLE;
m_aItems[i]->m_rect.OffsetRect(nOffset, 0);
m_aItems[i]->m_rectText.OffsetRect(nOffset, 0);
}
}//for tabs
}
//////////////////////////////////////////////////////////////////////////
//recalculate tab item rectangles (item rect and item text rect)
int CCustomTabCtrl::RecalcRectangles()
{
CRect rCl;
int i, w, h;
BOOL fTop;
int nWidth;
GetTabsRect(&rCl);
if(IsVertical())
{
rCl.SetRect(0, 0, rCl.Height(), rCl.Width());
}
fTop = GetStyle()&CTCS_TOP;
nWidth = 0;
{
//calculate widths
int nOffset = 0;
CRect rcText;
CDC* pDC = GetDC();
CFont* pOldFont = pDC->SelectObject(&m_FontSelected);
if(GetStyle()&CTCS_FIXEDWIDTH)
{
int nMaxWidth=0;
//get max width of items, based on item text
for(i=0; i<m_aItems.GetSize(); i++)
{
w=0;
h = pDC->DrawText(m_aItems[i]->m_sText, rcText, DT_CALCRECT);
if(h>0)
{
w = rcText.Width();
}
if(w>nMaxWidth)
{
nMaxWidth = w;
}
}//for items
for(i=0; i<m_aItems.GetSize(); i++)
{
if(fTop)
{
m_aItems[i]->m_rect = CRect(0, 0, nMaxWidth+rCl.Height()+4, rCl.bottom);
m_aItems[i]->m_rectText = CRect(rCl.Height()/2, 0, nMaxWidth+rCl.Height()/2+4, rCl.Height()-1);
}
else
{
m_aItems[i]->m_rect = CRect(0, rCl.top, nMaxWidth+rCl.Height()+4, rCl.bottom);
m_aItems[i]->m_rectText = CRect(rCl.Height()/2, rCl.top, nMaxWidth+rCl.Height()/2+4, rCl.bottom-1);
}
m_aItems[i]->m_rect += CPoint(nOffset, 0);
m_aItems[i]->m_rectText += CPoint(nOffset, 0);
//horizontal overlapping with height/2
//nOffset += m_aItems[i]->m_rect.Width()-rCl.Height()/2;
nOffset += m_aItems[i]->m_rect.Width();
nWidth = m_aItems[i]->m_rect.right;
}//for items
}//if fixed width
else
{
//variable width, calculate width based on individual text widths
for(i=0; i<m_aItems.GetSize(); i++)
{
w=0;
h = pDC->DrawText(m_aItems[i]->m_sText, rcText, DT_CALCRECT);
if(h>0)
{
w = rcText.Width();
}
if(fTop)
{
m_aItems[i]->m_rect = CRect(0, 0, w+rCl.Height()+4, rCl.bottom);
m_aItems[i]->m_rectText = CRect(rCl.Height()/2, 0, w+rCl.Height()/2+4, rCl.Height()-1);
}
else
{
m_aItems[i]->m_rect = CRect(0, rCl.top, w+rCl.Height()+4, rCl.bottom);
m_aItems[i]->m_rectText = CRect(rCl.Height()/2, rCl.top, w+rCl.Height()/2+4, rCl.bottom-1);
}
m_aItems[i]->m_rect += CPoint(nOffset, 0);
m_aItems[i]->m_rectText += CPoint(nOffset, 0);
//horizontal overlapping with height/2
//nOffset += m_aItems[i]->m_rect.Width()-rCl.Height()/2;
nOffset += m_aItems[i]->m_rect.Width();
nWidth = m_aItems[i]->m_rect.right;
}//for items
}//if not fixed width
pDC->SelectObject(pOldFont);
ReleaseDC(pDC);
}
return nWidth;
}
//////////////////////////////////////////////////////////////////////////
void CCustomTabCtrl::DrawGlyph(CDC& dc, CPoint& pt, int nImageNdx, int nColorNdx)
{
CDC dcMem, dcMemMono;
CBitmap bmpGlyphColor;
dcMem.CreateCompatibleDC(&dc);
dcMemMono.CreateCompatibleDC(&dc);
CBitmap* pOldBmpGlyphMono = dcMemMono.SelectObject(&m_bmpGlyphsMono);
bmpGlyphColor.CreateCompatibleBitmap(&dc, 8, 7);
CBitmap* pOldBmpGlyphColor = dcMem.SelectObject(&bmpGlyphColor);
COLORREF rgbOldTextGlyph = dcMem.SetTextColor(m_rgbGlyph[nColorNdx]);
dcMem.BitBlt(0, 0, 8, 7, &dcMemMono, nImageNdx*8, 0, SRCCOPY);
dcMem.SetTextColor(rgbOldTextGlyph);
COLORREF rgbOldBk = dc.SetBkColor(RGB(255, 255, 255));
COLORREF rgbOldText = dc.SetTextColor(RGB(0, 0, 0));
dc.BitBlt(pt.x, pt.y, 8, 7, &dcMem, 0, 0, SRCINVERT);
dc.BitBlt(pt.x, pt.y, 8, 7, &dcMemMono, nImageNdx*8, 0, SRCAND);
dc.BitBlt(pt.x, pt.y, 8, 7, &dcMem, 0, 0, SRCINVERT);
dcMem.SelectObject(pOldBmpGlyphColor);
dcMemMono.SelectObject(pOldBmpGlyphMono);
dc.SetBkColor(rgbOldBk);
dc.SetTextColor(rgbOldText);
}
//////////////////////////////////////////////////////////////////////////
BOOL CCustomTabCtrl::ModifyStyle(DWORD dwRemove, DWORD dwAdd, UINT nFlags)
{
int i;
if(dwRemove & CTCS_MULTIHIGHLIGHT)
{
//remove highlights
for(i=0; i<m_aItems.GetSize(); i++)
{
m_aItems[i]->m_fHighlighted = FALSE;
}
}
if(dwAdd & CTCS_MULTIHIGHLIGHT)
{
//highlight all selected tabs
for(i=0; i<m_aItems.GetSize(); i++)
{
if(i==m_nItemSelected)
{
m_aItems[i]->m_fHighlighted = TRUE;
}
}
}
//vertical styles removed
#ifdef _WIN32_WCE
dwAdd &= ~CTCS_LEFT;
dwAdd &= ~CTCS_RIGHT;
CWnd::ModifyStyle(dwRemove | CTCS_LEFT | CTCS_RIGHT, dwAdd, nFlags);
#else
CWnd::ModifyStyle(dwRemove, dwAdd, nFlags);
#endif
RecalcLayout(RECALC_RESIZED, m_nItemSelected);
Invalidate(FALSE);
return TRUE;
}
//////////////////////////////////////////////////////////////////////////
BOOL CCustomTabCtrl::ModifyStyleEx(DWORD dwRemove, DWORD dwAdd, UINT nFlags)
{
CWnd::ModifyStyleEx(dwRemove, dwAdd, nFlags);
RecalcLayout(RECALC_RESIZED, m_nItemSelected);
Invalidate(FALSE);
return TRUE;
}
//////////////////////////////////////////////////////////////////////////
void CCustomTabCtrl::PreSubclassWindow()
{
CWnd::ModifyStyle(0, WS_CLIPCHILDREN);
RecalcLayout(RECALC_RESIZED, m_nItemSelected);
CWnd::PreSubclassWindow();
}
//////////////////////////////////////////////////////////////////////////
#ifndef _WIN32_WCE
void CCustomTabCtrl::OnRButtonDown(UINT nFlags, CPoint point)
{
NotifyParent(CTCN_RCLICK, HitTest(point), point);
CWnd::OnRButtonDown(nFlags, point);
}
#endif
//////////////////////////////////////////////////////////////////////////
#ifndef _WIN32_WCE
void CCustomTabCtrl::OnRButtonDblClk(UINT nFlags, CPoint point)
{
NotifyParent(CTCN_RDBLCLK, HitTest(point), point);
CWnd::OnRButtonDblClk(nFlags, point);
}
#endif
//////////////////////////////////////////////////////////////////////////
int CCustomTabCtrl::EditLabel(int nItem)
{
return EditLabel(nItem, FALSE);
}
//////////////////////////////////////////////////////////////////////////
int CCustomTabCtrl::EditLabel(int nItem, BOOL fMouseSel)
{
if(nItem<0 || nItem>=m_aItems.GetSize())
{
return CTCERR_INDEXOUTOFRANGE;
}
if(!(GetStyle()&CTCS_EDITLABELS))
{
return CTCERR_NOEDITLABELSTYLE;
}
if(nItem!=m_nItemSelected)
{
return CTCERR_ITEMNOTSELECTED;
}
if(m_ctrlEdit.m_hWnd)
{
return CTCERR_ALREADYINEDITMODE;
}
if(IsVertical())
{
return CTCERR_EDITNOTSUPPORTED;
}
CRect r;
CDC* pDC = GetDC();
CFont* pOldFont = pDC->SelectObject(&m_FontSelected);
int h = pDC->DrawText(m_aItems[nItem]->m_sText, r, DT_CALCRECT);
pDC->SelectObject(pOldFont);
ReleaseDC(pDC);
r = m_aItems[nItem]->m_rectText;
if(r.Height()>h)
{
r.top += (r.Height()-h)/2;
r.bottom -= (r.Height()-h)/2;
}
r.left += 2;
//create edit control
if(m_ctrlEdit.Create(WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL, r, this, CTCID_EDITCTRL))
{
CString sOld = m_aItems[nItem]->m_sText;
m_ctrlEdit.SetFont(&m_FontSelected, FALSE);
m_ctrlEdit.SetLimitText(MAX_LABEL_LENGTH);
m_ctrlEdit.SetWindowText(m_aItems[nItem]->m_sText);
m_ctrlEdit.SetFocus();
m_ctrlEdit.SetSel(0,-1);
if(fMouseSel)
{
ReleaseCapture();
}
//process messages in edit mode
for(;;)
{
MSG msg;
::GetMessage(&msg, NULL, 0, 0);
switch (msg.message)
{
case WM_SYSKEYDOWN:
{
if(msg.wParam == VK_F4 && msg.lParam&29)
{
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
break;
}
case WM_KEYDOWN:
{
if (msg.wParam == VK_ESCAPE)
{
m_aItems[nItem]->m_sText = sOld;
m_ctrlEdit.DestroyWindow();
RecalcLayout(RECALC_RESIZED,m_nItemSelected);
Invalidate(FALSE);
return CTCERR_NOERROR;
}
if(msg.wParam == VK_RETURN)
{
if(NotifyParent(CTCN_LABELUPDATE,nItem,CPoint(0,0)))
break;
m_ctrlEdit.GetWindowText(m_aItems[nItem]->m_sText);
m_ctrlEdit.DestroyWindow();
RecalcLayout(RECALC_RESIZED,nItem);
Invalidate(FALSE);
return CTCERR_NOERROR;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
break;
}
case WM_LBUTTONDOWN:
{
if(msg.hwnd == m_hWnd)
{
POINTS pt = MAKEPOINTS(msg.lParam);
if(HitTest(CPoint(pt.x, pt.y)) != m_nItemSelected)
{
if(NotifyParent(CTCN_LABELUPDATE, nItem, CPoint(0, 0)))
{
break;
}
m_ctrlEdit.GetWindowText(m_aItems[m_nItemSelected]->m_sText);
m_ctrlEdit.DestroyWindow();
TranslateMessage(&msg);
DispatchMessage(&msg);
return CTCERR_NOERROR;
}
}
else if(msg.hwnd == m_ctrlEdit.m_hWnd)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
if(NotifyParent(CTCN_LABELUPDATE, nItem, CPoint(0, 0)))
{
break;
}
m_ctrlEdit.GetWindowText(m_aItems[m_nItemSelected]->m_sText);
m_ctrlEdit.DestroyWindow();
return CTCERR_NOERROR;
}
break;
}
case WM_LBUTTONUP:
{
if(msg.hwnd==m_ctrlEdit.m_hWnd)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
break;
}
case WM_LBUTTONDBLCLK:
#ifndef _WIN32_WCE
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
#endif
{
break;
}
default:
{
TranslateMessage(&msg);
DispatchMessage(&msg);
break;
}
}//switch message
}//for(ever)
}//if edit control created
return CTCERR_NOERROR;
}
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNAMIC(CCustomTabContainer, CCustomTabCtrl)
CCustomTabContainer::CCustomTabContainer()
{
}
//////////////////////////////////////////////////////////////////////////
CCustomTabContainer::~CCustomTabContainer()
{
int i;
for(i=0; i<m_Dlgs.GetSize(); i++)
{
delete m_Dlgs[i];
}
m_Dlgs.RemoveAll();
}
//////////////////////////////////////////////////////////////////////////
void CCustomTabContainer::FixStyle(HWND hWnd)
{
LONG lStyle;
lStyle=GetWindowLong(hWnd, GWL_STYLE);
lStyle &= ~WS_CAPTION;
lStyle &= ~DS_MODALFRAME;
lStyle &= ~WS_POPUP;
lStyle |= WS_CHILD;
SetWindowLong(hWnd, GWL_STYLE, lStyle);
}
BEGIN_MESSAGE_MAP(CCustomTabContainer, CCustomTabCtrl)
//{{AFX_MSG_MAP(MyTabCtrl)
ON_NOTIFY_REFLECT(CTCN_SELCHANGE, OnSelchange)
ON_NOTIFY_REFLECT(CTCN_CLICK, OnTabBtnClick)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// MyTabCtrl message handlers
//////////////////////////////////////////////////////////////////////////
void CCustomTabContainer::OnSelchange(NMHDR* pNMHDR, LRESULT* pResult)
{
Display();
*pResult = 0;
}
//////////////////////////////////////////////////////////////////////////
void CCustomTabContainer::OnTabBtnClick(NMHDR* pNMHDR, LRESULT* pResult)
{
CTC_NMHDR *pCHdr;
pCHdr=(CTC_NMHDR *)pNMHDR;
if(pCHdr->nItem == CTCID_CLOSEBUTTON)
{
//close
RemoveDialog(GetCurSel());
}
Display();
*pResult = 0;
}
//////////////////////////////////////////////////////////////////////////
void CCustomTabContainer::AddDialog(int nIndex, CString strText, CDialog *pDlg)
{
FixStyle(pDlg->GetSafeHwnd());
m_Dlgs.InsertAt(nIndex, pDlg);
if(strText != _T(""))
{
InsertItem(nIndex, strText);
}
else
{
InsertItem(nIndex, _T("<No title>"));
}
//nothing yet selected?
if(GetCurSel() < 0)
{
//select once
SetCurSel(nIndex);
Display();
}
}
//////////////////////////////////////////////////////////////////////////
void CCustomTabContainer::RemoveDialog(int nIndex)
{
if(nIndex >= 0 && nIndex < GetItemCount())
{
DeleteItem(nIndex);
delete m_Dlgs[nIndex];
m_Dlgs.RemoveAt(nIndex);
Display();
}
}
//////////////////////////////////////////////////////////////////////////
void CCustomTabContainer::Display()
{
int i, nSel;
CRect rcClient, rcWnd;
GetClientRect(rcClient);
GetWindowRect(rcWnd);
AdjustRect(FALSE, rcClient);
//no dialogs? then wipe background
if(m_Dlgs.GetCount() == 0)
{
CDC *pDC=GetDC();
if(pDC != NULL)
{
pDC->FillSolidRect(rcClient, m_ticColors.crWndBkg);
ReleaseDC(pDC);
}
}
nSel=GetCurSel();
if(nSel < 0 || nSel >= GetItemCount())
{
return;
}
if(m_Dlgs[nSel]->m_hWnd)
{
m_Dlgs[nSel]->ShowWindow(SW_HIDE);
}
GetParent()->ScreenToClient(rcWnd);
rcClient.OffsetRect(rcWnd.left, rcWnd.top);
for(i=0; i < m_Dlgs.GetCount(); i++)
{
m_Dlgs[i]->SetWindowPos(&wndTop, rcClient.left, rcClient.top, rcClient.Width(), rcClient.Height(), SWP_HIDEWINDOW);
}
m_Dlgs[nSel]->SetWindowPos(&wndTop, rcClient.left, rcClient.top, rcClient.Width(), rcClient.Height(), SWP_SHOWWINDOW);
m_Dlgs[nSel]->ShowWindow(SW_SHOW);
if(GetStyle() & CTCS_NOLINES)
{
return;
}
//once displayed, draw a line around dialog display area
/*
GetClientRect(rcClient);
AdjustRect(FALSE, rcClient);
CDC *pDC=GetDC();
if(pDC != NULL)
{
CPen pen(PS_SOLID, 1, m_ticColors.crDarkLine);
HGDIOBJ hOldPen;
hOldPen=pDC->SelectObject(pen);
if(GetStyle() & CTCS_TOP)
{
pDC->MoveTo(0, rcClient.top);
pDC->LineTo(0, rcClient.bottom);
pDC->LineTo(rcClient.right-1, rcClient.bottom);
pDC->LineTo(rcClient.right-1, rcClient.top);
}
else
{
pDC->MoveTo(0, rcClient.bottom);
pDC->LineTo(0, rcClient.top);
pDC->LineTo(rcClient.right-1, rcClient.top);
pDC->LineTo(rcClient.right-1, rcClient.bottom);
}
pDC->SelectObject(hOldPen);
ReleaseDC(pDC);
}
*/
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -