📄 bcgtabwnd.cpp
字号:
//*******************************************************************************
// COPYRIGHT NOTES
// ---------------
// This source code is a part of BCGControlBar library.
// You may use, compile or redistribute it as part of your application
// for free. You cannot redistribute it as a part of a software development
// library without the agreement of the author. If the sources are
// distributed along with the application, you should leave the original
// copyright notes in the source code without any changes.
// This code can be used WITHOUT ANY WARRANTIES on your own risk.
//
// Stas Levin <stas@iet.co.il>
//*******************************************************************************
// bcgtabwnd.cpp : implementation file
//
#include "stdafx.h"
#include "bcgtabwnd.h"
#include "globals.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
UINT BCGM_CHANGE_ACTIVE_TAB = ::RegisterWindowMessage (_T("BCGM_ONCHANGE_ACTIVE_TAB"));
UINT BCGM_ON_HSCROLL = ::RegisterWindowMessage (_T("BCGM_ON_HSCROLL"));
/////////////////////////////////////////////////////////////////////////////
// CBCGTabInfo
class CBCGTabInfo : public CObject
{
friend class CBCGTabWnd;
CBCGTabInfo(const CString& strText,
const UINT uiIcon,
CWnd* pWnd) :
m_pWnd (pWnd),
m_uiIcon (uiIcon)
{
m_strText = m_strDisplayedText = strText;
m_rect.SetRectEmpty ();
m_nFullWidth = 0;
}
CString m_strText;
CString m_strDisplayedText;
const UINT m_uiIcon;
CRect m_rect;
CWnd* m_pWnd;
int m_nFullWidth;
};
/////////////////////////////////////////////////////////////////////////////
// CBCGTabWnd
#define TAB_BORDER_SIZE 3
#define TEXT_MARGIN 4
#define IMAGE_MARGIN 4
#define MIN_SROLL_WIDTH (::GetSystemMetrics (SM_CXHSCROLL) * 2)
#define SPLITTER_WIDTH 5
#define TABS_FONT _T("Arial")
CBCGTabWnd::CBCGTabWnd()
{
m_iTabsNum = 0;
m_iActiveTab = -1;
m_sizeImage = CSize (0, 0);
m_bFlat = FALSE;
m_bSharedScroll = FALSE;
m_rectTabsArea.SetRectEmpty ();
m_rectWndArea.SetRectEmpty ();
m_nTabsHorzOffset = 0;
m_nTabsHorzOffsetMax = 0;
m_nTabsTotalWidth = 0;
m_nHorzScrollWidth = 0;
m_nScrollBarRight = 0;
m_rectTabSplitter.SetRectEmpty ();
m_bTrackSplitter = FALSE;
m_clrActiveTabBk = (COLORREF) -1;
m_clrActiveTabFg = (COLORREF) -1;
m_nTabsHeight = 0;
}
//***************************************************************************************
CBCGTabWnd::~CBCGTabWnd()
{
}
BEGIN_MESSAGE_MAP(CBCGTabWnd, CWnd)
//{{AFX_MSG_MAP(CBCGTabWnd)
ON_WM_DESTROY()
ON_WM_PAINT()
ON_WM_SIZE()
ON_WM_LBUTTONDOWN()
ON_WM_CREATE()
ON_WM_ERASEBKGND()
ON_WM_LBUTTONDBLCLK()
ON_WM_HSCROLL()
ON_WM_SETCURSOR()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_WM_CANCELMODE()
ON_WM_SYSCOLORCHANGE()
ON_WM_SETTINGCHANGE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
BOOL CBCGTabWnd::Create (Style style, const RECT& rect, CWnd* pParentWnd, UINT nID)
{
m_bFlat = (style == STYLE_FLAT) || (style == STYLE_FLAT_SHARED_HORZ_SCROLL);
m_bSharedScroll = style == STYLE_FLAT_SHARED_HORZ_SCROLL;
if (!m_bFlat && m_bSharedScroll)
{
//--------------------------------------
// Only flat tab has a shared scrollbar!
//--------------------------------------
ASSERT (FALSE);
m_bSharedScroll = FALSE;
}
return CWnd::Create (NULL, _T(""), WS_CHILD | WS_VISIBLE, rect,
pParentWnd, nID);
}
/////////////////////////////////////////////////////////////////////////////
// CBCGTabWnd message handlers
void CBCGTabWnd::OnDestroy()
{
for (int i = 0; i < m_iTabsNum; i ++)
{
CBCGTabInfo* pTab = (CBCGTabInfo*) m_arTabs [i];
ASSERT_VALID (pTab);
pTab->m_pWnd->DestroyWindow ();
delete pTab;
}
CWnd::OnDestroy();
}
//***************************************************************************************
void CBCGTabWnd::OnPaint()
{
CPaintDC dc(this); // device context for painting
CRect rectClient;
GetClientRect (&rectClient);
CBrush* pOldBrush = dc.SelectObject (&globalData.brBtnFace);
ASSERT (pOldBrush != NULL);
CPen penDrak (PS_SOLID, 1, globalData.clrBtnDkShadow);
CPen* pOldPen = (CPen*) dc.SelectObject (&penDrak);
ASSERT(pOldPen != NULL);
CRect rectTabs = rectClient;
rectTabs.top = m_rectTabsArea.top - TAB_BORDER_SIZE;
dc.FillRect (rectTabs, &globalData.brBtnFace);
CRect rectFrame = rectClient;
if (m_bFlat)
{
//---------------------------
// Draw line bellow the tabs:
//---------------------------
dc.MoveTo (rectFrame.left, m_rectTabsArea.top);
dc.LineTo (rectFrame.right, m_rectTabsArea.top);
}
else
{
rectFrame.bottom = m_rectTabsArea.top;
}
//-----------------------------------------------------
// Draw wide 3-dimensional frame around the Tabs area:
//-----------------------------------------------------
dc.Draw3dRect (&rectFrame, globalData.clrBtnHilite, globalData.clrBtnDkShadow);
rectFrame.DeflateRect (1, 1);
dc.Draw3dRect (&rectFrame,
globalData.clrBtnLight, globalData.clrBtnShadow);
rectFrame.DeflateRect (1, 1);
if (rectFrame.Width () > 0 && rectFrame.Height () > 0)
{
dc.PatBlt (rectFrame.left, rectFrame.top, TAB_BORDER_SIZE, rectFrame.Height (), PATCOPY);
dc.PatBlt (rectFrame.left, rectFrame.top, rectFrame.Width (), TAB_BORDER_SIZE, PATCOPY);
dc.PatBlt (rectFrame.right - TAB_BORDER_SIZE, rectFrame.top, TAB_BORDER_SIZE, rectFrame.Height (), PATCOPY);
dc.PatBlt (rectFrame.left, rectFrame.bottom - TAB_BORDER_SIZE, rectFrame.Width (), TAB_BORDER_SIZE, PATCOPY);
rectFrame.DeflateRect (TAB_BORDER_SIZE - 2, TAB_BORDER_SIZE - 2);
if (rectFrame.Width () > 0 && rectFrame.Height () > 0)
{
dc.Draw3dRect (&rectFrame,
globalData.clrBtnDkShadow, globalData.clrBtnHilite);
}
}
CFont* pOldFont = dc.SelectObject (m_bFlat ? &m_fntTabs :
&globalData.fontRegular);
ASSERT(pOldFont != NULL);
dc.SetBkMode (TRANSPARENT);
dc.SetTextColor (globalData.clrBtnText);
if (m_rectTabsArea.Width () > 2 * TAB_BORDER_SIZE + 1 &&
m_rectTabsArea.Height () > 2 * TAB_BORDER_SIZE + 1)
{
//-----------
// Draw tabs:
//-----------
if (m_bFlat)
{
CRgn rgn;
rgn.CreateRectRgnIndirect (m_rectTabsArea);
dc.SelectClipRgn (&rgn);
}
for (int i = 0; i < m_iTabsNum; i ++)
{
CBCGTabInfo* pTab = (CBCGTabInfo*) m_arTabs [i];
ASSERT_VALID (pTab);
if (m_bFlat)
{
if (i != m_iActiveTab) // Draw active button last
{
DrawFlatTab (&dc, pTab, FALSE);
}
}
else
{
Draw3DTab (&dc, pTab, i == m_iActiveTab);
}
}
if (m_bFlat && m_iActiveTab >= 0)
{
//-----------------
// Draw active tab:
//-----------------
CBCGTabInfo* pTabActive = (CBCGTabInfo*) m_arTabs [m_iActiveTab];
ASSERT_VALID (pTabActive);
dc.SelectObject (&m_brActiveTab);
dc.SelectObject (&m_fntTabsBold);
dc.SetTextColor (GetActiveTabTextColor ());
DrawFlatTab (&dc, pTabActive, TRUE);
//---------------------------------
// Draw line bellow the active tab:
//---------------------------------
CPen penLight (PS_SOLID, 1, GetActiveTabColor ());
dc.SelectObject (&penLight);
dc.MoveTo (pTabActive->m_rect.left + 1, pTabActive->m_rect.top);
dc.LineTo (pTabActive->m_rect.right, pTabActive->m_rect.top);
}
if (m_bFlat)
{
dc.SelectClipRgn (NULL);
}
}
if (!m_rectTabSplitter.IsRectEmpty ())
{
dc.FillRect (m_rectTabSplitter, &globalData.brBtnFace);
CRect rectTabSplitter = m_rectTabSplitter;
dc.Draw3dRect (rectTabSplitter,
globalData.clrBtnDkShadow, globalData.clrBtnShadow);
rectTabSplitter.DeflateRect (1, 1);
dc.Draw3dRect (rectTabSplitter,
globalData.clrBtnHilite, globalData.clrBtnShadow);
}
dc.SelectObject (pOldFont);
dc.SelectObject (pOldBrush);
dc.SelectObject (pOldPen);
}
//***************************************************************************************
void CBCGTabWnd::OnSize(UINT nType, int cx, int cy)
{
CWnd::OnSize(nType, cx, cy);
int nTabsAreaWidth = cx - 4 * ::GetSystemMetrics (SM_CXVSCROLL)
- 2 * TAB_BORDER_SIZE;
if (nTabsAreaWidth <= MIN_SROLL_WIDTH)
{
m_nHorzScrollWidth = 0;
}
else if (nTabsAreaWidth / 2 > MIN_SROLL_WIDTH)
{
m_nHorzScrollWidth = nTabsAreaWidth / 2;
}
else
{
m_nHorzScrollWidth = nTabsAreaWidth;
}
RecalcLayout ();
SynchronizeScrollBar ();
}
//***************************************************************************************
void CBCGTabWnd::AddTab (CWnd* pNewWnd, LPCTSTR lpszName, UINT uiImageId)
{
ASSERT_VALID (this);
ASSERT_VALID (pNewWnd);
ASSERT (pNewWnd->GetParent()->GetSafeHwnd () == GetSafeHwnd ());
ASSERT (lpszName != NULL);
if (m_bFlat)
{
ASSERT (uiImageId == -1);
uiImageId = (UINT) -1;
}
else if (m_sizeImage != CSize (0, 0))
{
ASSERT (uiImageId != (UINT) -1);
}
m_arTabs.SetAtGrow (m_iTabsNum ++,
new CBCGTabInfo (lpszName, uiImageId, pNewWnd));
if (!m_bFlat)
{
CRect rectEmpty (0, 0, 0, 0);
m_ToolTip.AddTool (this, lpszName, &rectEmpty, m_iTabsNum);
}
RecalcLayout ();
if (m_iTabsNum == 1)
{
//----------------------------------------
// First tab automatically becames active:
//----------------------------------------
SetActiveTab (0);
}
if (GetActiveWnd () != pNewWnd)
{
pNewWnd->ShowWindow (SW_HIDE);
}
}
//***************************************************************************************
BOOL CBCGTabWnd::RemoveTab (int iTab)
{
if (iTab < 0 || iTab >= m_iTabsNum)
{
TRACE(_T("RemoveTab: illegal tab number %d\n"), iTab);
return FALSE;
}
if (m_iTabsNum == 1)
{
RemoveAllTabs ();
return TRUE;
}
CBCGTabInfo* pTab = (CBCGTabInfo*) m_arTabs [iTab];
ASSERT_VALID (pTab);
//----------------------------
// Detach tab from collection:
//----------------------------
m_arTabs.RemoveAt (iTab);
m_iTabsNum --;
//-----------------------------------
// Destroy tab window and delete tab:
//-----------------------------------
ASSERT_VALID (pTab->m_pWnd);
pTab->m_pWnd->DestroyWindow ();
delete pTab;
int iActiveTab = -1;
if (m_iActiveTab >= iTab)
{
iActiveTab = max (0, min (m_iTabsNum, m_iActiveTab - 1));
m_iActiveTab = -1;
}
RecalcLayout ();
SetActiveTab (iActiveTab);
GetParent ()->SendMessage (BCGM_CHANGE_ACTIVE_TAB, m_iActiveTab);
return TRUE;
}
//***************************************************************************************
void CBCGTabWnd::RemoveAllTabs ()
{
for (int i = 0; i < m_iTabsNum; i ++)
{
CBCGTabInfo* pTab = (CBCGTabInfo*) m_arTabs [i];
ASSERT_VALID (pTab);
pTab->m_pWnd->DestroyWindow ();
delete pTab;
}
m_arTabs.RemoveAll ();
m_iTabsNum = 0;
m_iActiveTab = -1;
RecalcLayout ();
}
//***************************************************************************************
BOOL CBCGTabWnd::SetActiveTab (int iTab)
{
if (iTab < 0 || iTab >= m_iTabsNum)
{
TRACE(_T("SetActiveTab: illegal tab number %d\n"), iTab);
return FALSE;
}
if (m_iActiveTab == iTab) // Already active, do nothing
{
return TRUE;
}
if (m_iActiveTab != -1)
{
//--------------------
// Hide active window:
//--------------------
GetActiveWnd()->ShowWindow (SW_HIDE);
}
m_iActiveTab = iTab;
//------------------------
// Show new active window:
//------------------------
HideActiveWindowHorzScrollBar ();
GetActiveWnd ()->ShowWindow (SW_SHOW);
//----------------------------------------------------------------------
// Small trick: to adjust active window scroll sizes, I should change an
// active window size twice (+1 pixel and -1 pixel):
//----------------------------------------------------------------------
GetActiveWnd ()->SetWindowPos (NULL,
-1, -1,
m_rectWndArea.Width (), m_rectWndArea.Height (),
SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
GetActiveWnd ()->SetWindowPos (NULL,
-1, -1,
m_rectWndArea.Width () - 1, m_rectWndArea.Height (),
SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
EnsureVisible (m_iActiveTab);
if (m_bFlat)
{
SynchronizeScrollBar ();
}
//-------------
// Redraw tabs:
//-------------
Invalidate ();
UpdateWindow ();
return TRUE;
}
//***************************************************************************************
void CBCGTabWnd::AdjustTabs ()
{
m_nTabsTotalWidth = 0;
if (m_iTabsNum == 0)
{
return;
}
//-------------------------
// Define tab's full width:
//-------------------------
CClientDC dc (this);
CFont* pOldFont = dc.SelectObject (m_bFlat ?
&m_fntTabsBold : &globalData.fontRegular);
ASSERT(pOldFont != NULL);
CRect rectClient;
GetClientRect (&rectClient);
//----------------------------------------------
// First, try set all tabs in its original size:
//----------------------------------------------
int x = m_rectTabsArea.left - m_nTabsHorzOffset;
for (int i = 0; i < m_iTabsNum; i ++)
{
CBCGTabInfo* pTab = (CBCGTabInfo*) m_arTabs [i];
ASSERT_VALID (pTab);
pTab->m_nFullWidth = m_sizeImage.cx + IMAGE_MARGIN +
dc.GetTextExtent (pTab->m_strText).cx + 2 * TEXT_MARGIN;
pTab->m_rect = CRect (CPoint (x, m_rectTabsArea.top),
CSize (pTab->m_nFullWidth, m_rectTabsArea.Height () - 2));
if (!m_bFlat)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -