📄 ftab.cpp
字号:
dc.LineTo(rc.right, rc.top);
if (m_dwFtabStyle & FTS_FULLBORDER) {
dc.MoveTo(rc.right-1, rc.top);
dc.LineTo(rc.right-1, rc.bottom-1);
dc.LineTo(rc.left, rc.bottom-1);
dc.LineTo(rc.left, rc.top);
} else {
dc.MoveTo(rc.left, rc.top);
}
dc.LineTo(rcCurTab.TopLeft());
dc.SelectObject(pOldPen);
}
//////////////////
// Handle mouse click: select new tab, if any. Notify parent, of course
//
void CFolderTabCtrl::OnLButtonDown(UINT nFlags, CPoint pt)
{
int iTab = HitTest(pt);
if (iTab>=0 && iTab!=m_iCurItem) {
SelectItem(iTab);
NMFOLDERTAB nm;
nm.hwndFrom = m_hWnd;
nm.idFrom = GetDlgCtrlID();
nm.code = FTN_TABCHANGED;
nm.iItem = iTab;
CWnd* pParent = GetParent();
pParent->SendMessage(WM_NOTIFY, nm.idFrom, (LPARAM)&nm);
}
}
//////////////////
// Find which tab is under mouse, -1 if none
//
int CFolderTabCtrl::HitTest(CPoint pt)
{
CRect rc;
GetClientRect(&rc);
rc.left += m_cxButtons;
if (rc.PtInRect(pt)) {
int xOrigin = m_cxButtons - GetTab(m_iFirstTab)->GetRect().left;
pt.x -= xOrigin;
int n = GetItemCount();
for (int i=0; i<n; i++) {
if (GetTab(i)->HitTest(pt))
return i;
}
}
return -1;
}
//////////////////
// Select ith tab. Returns index selected
//
int CFolderTabCtrl::SelectItem(int iTab)
{
int count = GetItemCount();
if (iTab<0 || iTab>=count)
return -1; // bad
if (iTab == m_iCurItem)
return iTab; // already selected
if (m_iCurItem < count)
InvalidateTab(m_iCurItem); // invalidate old tab (repaint)
m_iCurItem = iTab; // set new selected tab
InvalidateTab(m_iCurItem); // repaint new tab
return m_iCurItem;
}
//////////////////
/// Invalidate a tab: invaldate its rect
//
void CFolderTabCtrl::InvalidateTab(int iTab, BOOL bErase)
{
CRect rc = GetTab(iTab)->GetRect();
int xOrigin = m_cxButtons - GetTab(m_iFirstTab)->GetRect().left;
rc += CPoint(xOrigin,0);
InvalidateRect(rc, bErase);
}
//////////////////
// Load folder tab control from resource string:
// newline-separated list of tab names.
//
BOOL CFolderTabCtrl::Load(UINT nIDRes)
{
CString s;
if (!s.LoadString(nIDRes))
return FALSE;
CString sTab;
for (int i=0; AfxExtractSubString(sTab, s, i); i++) {
AddItem(sTab);
}
return TRUE;
}
//////////////////
// Add a tab.
//
int CFolderTabCtrl::AddItem(LPCTSTR lpszText)
{
m_lsTabs.AddTail(new CFolderTab(lpszText));
RecomputeLayout();
return m_lsTabs.GetCount() - 1;
}
//////////////////
// Remove tab at given index.
//
BOOL CFolderTabCtrl::RemoveItem(int iPos)
{
POSITION pos = m_lsTabs.FindIndex(iPos);
if (pos) {
CFolderTab* pTab = (CFolderTab*)m_lsTabs.GetAt(pos);
m_lsTabs.RemoveAt(pos);
delete pTab;
}
RecomputeLayout();
return pos!=NULL;
}
CFolderTab* CFolderTabCtrl::GetTab(int iPos)
{
POSITION pos = m_lsTabs.FindIndex(iPos);
return pos ? static_cast<CFolderTab*>(m_lsTabs.GetAt(pos)) : NULL;
}
//////////////////
// Recalculate layout based on having added or removed a tab.
//
void CFolderTabCtrl::RecomputeLayout()
{
CClientDC dc(this);
CFont* pOldFont = dc.SelectObject(&m_fontNormal);
int x = 0;
int n = GetItemCount();
CFolderTab* pTab;
for (int i=0; i<n; i++) {
pTab = GetTab(i);
if (pTab)
x += pTab->ComputeRgn(dc, x) - CXOFFSET;
}
dc.SelectObject(pOldFont);
m_cxDesired = m_cxButtons;
if (pTab) {
CRect rc = pTab->GetRect();
m_cxDesired += rc.right;
}
}
//////////////////
// Folder tabs changed size: reposition scroll buttons.
//
void CFolderTabCtrl::OnSize(UINT nType, int cx, int cy)
{
if (m_wndButton[0].m_hWnd) {
int w = cy;
CRect rc(0,0,w,cy);
for (int i=FTBPREV; i<=FTBNEXT; i++) {
m_wndButton[i-1].MoveWindow(&rc);
rc += CPoint(w,0);
}
UpdateButtons();
}
}
//////////////////
// Determine enabled state of scroll buttons
//
void CFolderTabCtrl::UpdateButtons()
{
if (m_wndButton[0].m_hWnd && !m_lsTabs.IsEmpty()) {
// enable prev button iff more tabs to left.
m_wndButton[0].EnableWindow(m_iFirstTab>0);
// enable next button iff more tabs to right
CRect rc;
GetClientRect(&rc);
int xOrigin = m_cxButtons - GetTab(m_iFirstTab)->GetRect().left;
CRect rcLast = ((CFolderTab*)m_lsTabs.GetTail())->GetRect();
m_wndButton[1].EnableWindow(xOrigin + rcLast.right>rc.right);
}
}
//////////////////
// User clicked next button: increment starting tab and repaint
//
void CFolderTabCtrl::OnNextTab()
{
if (m_iFirstTab < m_lsTabs.GetCount()-1) {
m_iFirstTab++;
Invalidate();
UpdateButtons();
}
}
//////////////////
// User clicked prev button: decrement starting tab and repaint
//
void CFolderTabCtrl::OnPrevTab()
{
if (m_iFirstTab > 0) {
m_iFirstTab--;
Invalidate();
UpdateButtons();
}
}
////////////////////////////////////////////////////////////////
// CFolderButton
//
IMPLEMENT_DYNAMIC(CFolderButton, CButton)
BEGIN_MESSAGE_MAP(CFolderButton, CButton)
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_LBUTTONDBLCLK()
ON_WM_TIMER()
END_MESSAGE_MAP()
//////////////////
// Draw sroll button: draw a black triangle.
//
void CFolderButton::DrawItem(LPDRAWITEMSTRUCT lpDis)
{
DRAWITEMSTRUCT& dis = *lpDis;
CDC& dc = *CDC::FromHandle(dis.hDC);
CRect rc;
GetClientRect(&rc);
// fill background with 3D face color
dc.FillSolidRect(&rc,GetSysColor(COLOR_3DFACE));
// shift southeast if button is pressed (bDown)
BOOL bDown = dis.itemState & ODS_SELECTED;
if (bDown) {
rc += CPoint(1,1);
}
// draw line above to match folder tabs
CPen pen(PS_SOLID,1,
dis.itemState & ODS_DISABLED ? GetSysColor(COLOR_3DSHADOW) : RGB(0,0,0));
CPen* pOldPen = dc.SelectObject(&pen);
dc.MoveTo(rc.TopLeft());
dc.LineTo(rc.right,rc.top);
// Draw 3D highlight rect for 3D look
CRect rc2=rc;
for (int i=0; i<2; i++) {
dc.Draw3dRect(&rc2,
GetSysColor(bDown ? COLOR_3DFACE : COLOR_3DHIGHLIGHT),
GetSysColor(COLOR_3DSHADOW));
rc2.right--;
rc2.bottom--;
}
// Draw triangle pointing the right way. Use shadow color if disabled.
CSize szArrow = CSize(4,7);
int cyMargin = (rc.Height()-szArrow.cy)/2;
int cxMargin = (rc.Width()-szArrow.cx)/2;
int x, incr;
if (dis.CtlID==FTBNEXT) {
x = rc.left + cxMargin;
incr = 1;
} else {
x = rc.right - cxMargin - 1;
incr = -1;
}
int y = rc.top + cyMargin;
int h = 7;
for (int j=0; j<4; j++) {
dc.MoveTo(x,y);
dc.LineTo(x,y+h);
h-=2;
x += incr;
y++;
}
dc.SelectObject(pOldPen);
}
//////////////////
// User clicked button.
//
void CFolderButton::OnLButtonDown(UINT nFlags, CPoint pt)
{
Default(); // will send WM_COMMAND to parent
SetTimer(1,500,NULL); // set timer for continual scroll
m_nTimerClick = 0; // counter for initial delay
}
//////////////////
// User let go the mouse.
//
void CFolderButton::OnLButtonUp(UINT nFlags, CPoint pt)
{
KillTimer(1); // no more repeat
Default();
}
//////////////////
// Double-click: treat as another click.
//
void CFolderButton::OnLButtonDblClk(UINT nFlags, CPoint pt)
{
SendMessage(WM_LBUTTONDOWN,nFlags,MAKELONG(pt.x,pt.y));
}
//////////////////
// Timer click: send another WM_COMMMAND, as if button clicked.
//
void CFolderButton::OnTimer(UINT nIDEvent)
{
if (IsWindowEnabled()) {
if (m_nTimerClick++ == 0) {
KillTimer(1);
SetTimer(1,150,NULL);
}
GetParent()->SendMessage(WM_COMMAND, GetDlgCtrlID());
} else {
KillTimer(1);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -