📄 ftab.cpp
字号:
////////////////////////////////////////////////////////////////
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// Compiles with Visual Studio 6.0 on Windows XP. Tab size=3.
//
#include "stdafx.h"
#include "ftab.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//////////////////
// Private class to represent one folder tab
//
class CFolderTab {
private:
CString m_sText; // tab text
CRect m_rect; // bounding rect
CRgn m_rgn; // polygon region to fill (trapezoid)
int ComputeRgn(CDC& dc, int x);
int Draw(CDC& dc, CFont& font, BOOL bSelected);
BOOL HitTest(CPoint pt) { return m_rgn.PtInRegion(pt); }
CRect GetRect() const { return m_rect; }
void GetTrapezoid(const CRect& rc, CPoint* pts) const;
friend class CFolderTabCtrl;
public:
CFolderTab(LPCTSTR lpszText) : m_sText(lpszText) { }
LPCTSTR GetText() const { return m_sText; }
void SetText(LPCTSTR lpszText) { m_sText = lpszText; }
};
const CXOFFSET = 8; // defined pitch of trapezoid slant
const CXMARGIN = 2; // left/right text margin
const CYMARGIN = 1; // top/bottom text margin
const CYBORDER = 1; // top border thickness
const CXBUTTON = GetSystemMetrics(SM_CXVSCROLL);
//////////////////
// Compute the the points, rect and region for a tab.
// Input x is starting x pos.
//
int CFolderTab::ComputeRgn(CDC& dc, int x)
{
m_rgn.DeleteObject();
CRect& rc = m_rect;
rc.SetRectEmpty();
// calculate desired text rectangle
dc.DrawText(m_sText, &rc, DT_CALCRECT);
rc.right += 2*CXOFFSET + 2*CXMARGIN; // add margins
rc.bottom = rc.top + GetSystemMetrics(SM_CYHSCROLL); // ht = scrollbar ht
rc += CPoint(x,0); // shift right
// create trapezoid region
CPoint pts[4];
GetTrapezoid(rc, pts);
m_rgn.CreatePolygonRgn(pts, 4, WINDING);
return rc.Width();
}
//////////////////
// Given the boundint rect, compute trapezoid region.
// Note that the right and bottom edges not included in rect or
// trapezoid; these are normal rules of geometry.
//
void CFolderTab::GetTrapezoid(const CRect& rc, CPoint* pts) const
{
pts[0] = rc.TopLeft();
pts[1] = CPoint(rc.left + CXOFFSET, rc.bottom);
pts[2] = CPoint(rc.right- CXOFFSET-1, rc.bottom);
pts[3] = CPoint(rc.right-1, rc.top);
}
//////////////////
// Draw tab in normal or highlighted state
//
int CFolderTab::Draw(CDC& dc, CFont& font, BOOL bSelected)
{
COLORREF bgColor = GetSysColor(bSelected ? COLOR_WINDOW : COLOR_3DFACE);
COLORREF fgColor = GetSysColor(bSelected ? COLOR_WINDOWTEXT : COLOR_BTNTEXT);
CBrush brush(bgColor); // background brush
dc.SetBkColor(bgColor); // text background
dc.SetTextColor(fgColor); // text color = fg color
CPen blackPen(PS_SOLID, 1, RGB(0,0,0)); // black
CPen shadowPen(PS_SOLID, 1, GetSysColor(COLOR_3DSHADOW));
// Fill trapezoid
CPoint pts[4];
CRect rc = m_rect;
GetTrapezoid(rc, pts);
CPen* pOldPen = dc.SelectObject(&blackPen);
dc.FillRgn(&m_rgn, &brush);
// Draw edges. This is requires two corrections:
// 1) Trapezoid dimensions don't include the right and bottom edges,
// so must use one pixel less on bottom (cybottom)
// 2) the endpoint of LineTo is not included when drawing the line, so
// must add one pixel (cytop)
//
pts[1].y--; // correction #1: true bottom edge y-coord
pts[2].y--; // ...ditto
pts[3].y--; // correction #2: extend final LineTo
dc.MoveTo(pts[0]); // upper left
dc.LineTo(pts[1]); // bottom left
dc.SelectObject(&shadowPen); // bottom line is shadow color
dc.MoveTo(pts[1]); // line is inside trapezoid bottom
dc.LineTo(pts[2]); // ...
dc.SelectObject(&blackPen); // upstroke is black
dc.LineTo(pts[3]); // y-1 to include endpoint
if (!bSelected) {
// if not highlighted, upstroke has a 3D shadow, one pixel inside
pts[2].x--; // offset left one pixel
pts[3].x--; // ...ditto
dc.SelectObject(&shadowPen);
dc.MoveTo(pts[2]);
dc.LineTo(pts[3]);
}
dc.SelectObject(pOldPen);
// draw text
rc.DeflateRect(CXOFFSET + CXMARGIN, CYMARGIN);
CFont* pOldFont = dc.SelectObject(&font);
dc.DrawText(m_sText, &rc, DT_CENTER|DT_VCENTER|DT_SINGLELINE);
dc.SelectObject(pOldFont);
return m_rect.right;
}
//////////////////////////////////////////////////////////////////
// CFolderTabCtrl
IMPLEMENT_DYNAMIC(CFolderTabCtrl, CWnd)
BEGIN_MESSAGE_MAP(CFolderTabCtrl, CWnd)
ON_WM_CREATE()
ON_WM_PAINT()
ON_WM_SIZE()
ON_WM_LBUTTONDOWN()
ON_BN_CLICKED(FTBPREV,OnPrevTab)
ON_BN_CLICKED(FTBNEXT,OnNextTab)
END_MESSAGE_MAP()
CFolderTabCtrl::CFolderTabCtrl()
{
m_iCurItem =
m_dwFtabStyle =
m_cxDesired =
m_cxButtons =
m_iFirstTab = 0;
}
CFolderTabCtrl::~CFolderTabCtrl()
{
while (!m_lsTabs.IsEmpty())
delete (CFolderTab*)m_lsTabs.RemoveHead();
}
//////////////////
// Create folder tab control from static control.
// Destroys the static control. This is convenient for dialogs
//
BOOL CFolderTabCtrl::CreateFromStatic(UINT nID, CWnd* pParent)
{
CStatic wndStatic;
if (!wndStatic.SubclassDlgItem(nID, pParent))
return FALSE;
CRect rc;
wndStatic.GetWindowRect(&rc);
pParent->ScreenToClient(&rc);
wndStatic.DestroyWindow();
rc.bottom = rc.top + GetDesiredHeight();
return Create(WS_CHILD|WS_VISIBLE, rc, pParent, nID);
}
//////////////////
// Create folder tab control.
//
BOOL CFolderTabCtrl::Create(DWORD dwStyle, const RECT& rc,
CWnd* pParent, UINT nID, DWORD dwFtabStyle)
{
ASSERT(pParent);
ASSERT(dwStyle & WS_CHILD);
m_dwFtabStyle = dwFtabStyle;
static LPCTSTR lpClassName = _T("PDFolderTab");
static BOOL bRegistered = FALSE; // registered?
if (!bRegistered) {
WNDCLASS wc;
memset(&wc, 0, sizeof(wc));
wc.style = CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS;
wc.lpfnWndProc = (WNDPROC)::DefWindowProc; // will get hooked by MFC
wc.hInstance = AfxGetInstanceHandle();
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = CreateSolidBrush(GetSysColor(COLOR_3DFACE));
wc.lpszMenuName = NULL;
wc.lpszClassName = lpClassName;
if (!AfxRegisterClass(&wc)) {
TRACE("*** CFolderTabCtrl::AfxRegisterClass failed!\n");
return FALSE;
}
bRegistered = TRUE;
}
if (!CWnd::CreateEx(0, lpClassName, NULL, dwStyle, rc, pParent, nID))
return FALSE;
// initialize fonts
LOGFONT lf;
memset(&lf, 0, sizeof(lf));
lf.lfHeight = GetSystemMetrics(SM_CYHSCROLL)-CYMARGIN;
lf.lfWeight = FW_NORMAL;
lf.lfCharSet = DEFAULT_CHARSET;
_tcscpy(lf.lfFaceName, _T("Arial"));
m_fontNormal.CreateFontIndirect(&lf);
lf.lfHeight -= 2;
m_fontSelected.CreateFontIndirect(&lf);
return TRUE;
}
//////////////////
// Folder tab was created: create scroll buttons if style says so.
//
int CFolderTabCtrl::OnCreate(LPCREATESTRUCT lpcs)
{
if (CWnd::OnCreate(lpcs)!=0)
return -1;
if (m_dwFtabStyle & FTS_BUTTONS) {
CRect rc;
for (int id=FTBPREV; id<=FTBNEXT; id++) {
VERIFY(m_wndButton[id-1].Create(WS_VISIBLE|WS_CHILD, this, rc, id));
}
m_cxButtons = 2*CXBUTTON;
}
return 0;
}
//////////////////
// Get folder tab text
//
LPCTSTR CFolderTabCtrl::GetItemText(int iItem)
{
CFolderTab* pft = GetTab(iItem);
return pft ? pft->GetText() : NULL;
}
//////////////////
// Set folder tab text
//
void CFolderTabCtrl::SetItemText(int iItem, LPCTSTR lpText)
{
CFolderTab* pft = GetTab(iItem);
if (pft) {
pft->SetText(lpText);
}
}
//////////////////
// copy a font
//
static void CopyFont(CFont& dst, CFont& src)
{
dst.DeleteObject();
LOGFONT lf;
VERIFY(src.GetLogFont(&lf));
dst.CreateFontIndirect(&lf);
}
//////////////////
// Set normal, selected fonts
//
void CFolderTabCtrl::SetFonts(CFont& fontNormal, CFont& fontSelected)
{
CopyFont(m_fontNormal, fontNormal);
CopyFont(m_fontSelected, fontSelected);
}
//////////////////
// Paint function
//
void CFolderTabCtrl::OnPaint()
{
CPaintDC dc(this); // device context for painting
int xOrigin = m_cxButtons - GetTab(m_iFirstTab)->GetRect().left;
dc.SetViewportOrg(xOrigin,0);
CRect rc;
GetClientRect(&rc);
CFolderTab* pCurTab = NULL;
// draw all the normal (non-selected) tabs
int n = GetItemCount();
for (int i=0; i<n; i++) {
CFolderTab* pTab = GetTab(i);
ASSERT(pTab);
if (i==m_iCurItem) {
pCurTab = pTab;
} else {
pTab->Draw(dc, m_fontNormal, FALSE);
}
}
// draw selected tab last so it will be "on top" of the others
if (pCurTab)
pCurTab->Draw(dc, m_fontSelected, TRUE);
// draw border: line along the top edge, excluding seleted tab
CRect rcCurTab(0,0,0,0);
if (pCurTab)
rcCurTab = pCurTab->GetRect();
rc.right -= xOrigin;
CPen blackPen(PS_SOLID, 1, RGB(0,0,0)); // black
CPen* pOldPen = dc.SelectObject(&blackPen);
dc.MoveTo(rcCurTab.right, rcCurTab.top);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -