1729 lines
40 KiB
C++
1729 lines
40 KiB
C++
// ==========================================================================
|
|
// Class Implementation :
|
|
// COXTabViewContainer
|
|
// ==========================================================================
|
|
|
|
// Version: 9.3
|
|
|
|
// This software along with its related components, documentation and files ("The Libraries")
|
|
// is © 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
|
|
// governed by a software license agreement ("Agreement"). Copies of the Agreement are
|
|
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
|
|
// to obtain this file, or directly from our office. For a copy of the license governing
|
|
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.
|
|
|
|
// //////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
#include "stdafx.h"
|
|
#include "OXTabView.h"
|
|
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
|
|
COXTabViewContainer* PASCAL GetParentTabViewContainer(CWnd* pWnd,
|
|
BOOL bOnlyActive/*=TRUE*/)
|
|
{
|
|
#if defined (_WINDLL)
|
|
#if defined (_AFXDLL)
|
|
AFX_MANAGE_STATE(AfxGetAppModuleState());
|
|
#else
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
#endif
|
|
#endif
|
|
|
|
ASSERT(pWnd!=NULL);
|
|
HWND hWndParent=::GetParent(pWnd->GetSafeHwnd());
|
|
if(hWndParent==NULL)
|
|
return NULL;
|
|
|
|
COXTabViewContainer* pContainer=
|
|
(COXTabViewContainer*)CWnd::FromHandlePermanent(hWndParent);
|
|
if(pContainer!=NULL)
|
|
{
|
|
ASSERT(::IsWindow(pContainer->m_hWnd));
|
|
if(::IsWindow(pContainer->m_hWnd))
|
|
{
|
|
if(::GetWindowLongPtr(pContainer->m_hWnd,GWL_USERDATA)==
|
|
ID_TABVIEWCONTAINER_SIGN)
|
|
{
|
|
if(!bOnlyActive || pContainer->IsActivePage(pWnd))
|
|
{
|
|
return pContainer;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// COXTabViewContainer
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
IMPLEMENT_DYNCREATE(COXTabViewContainer,CWnd)
|
|
|
|
COXTabViewContainer::COXTabViewContainer()
|
|
{
|
|
EmptyRects();
|
|
m_nLastTabBtnAreaWidth=-1;
|
|
m_nTabBtnAreaOrigin=0;
|
|
|
|
m_arrUniqueIDs.Add(1);
|
|
m_nActivePageIndex=-1;
|
|
|
|
m_nPressedScrlBtn=NONE;
|
|
m_bIsScrlBtnPressed=FALSE;
|
|
m_nScrollPageTimer=-1;
|
|
|
|
m_bIsSplitterPressed=FALSE;
|
|
|
|
m_nLastTabBtnAreaWidth=ID_INITABBTNAREAWIDTH;
|
|
|
|
if((HFONT)m_fontTabBtnText==NULL)
|
|
m_fontTabBtnText.CreatePointFont(80,_T("MS Sans Serif"));
|
|
if((HFONT)m_fontActiveTabBtnText==NULL && (HFONT)m_fontTabBtnText!=NULL)
|
|
{
|
|
LOGFONT lf;
|
|
if(m_fontTabBtnText.GetLogFont(&lf)!=0)
|
|
{
|
|
lf.lfWeight=FW_BOLD;
|
|
m_fontActiveTabBtnText.CreateFontIndirect(&lf);
|
|
}
|
|
}
|
|
|
|
ASSERT((HFONT)m_fontTabBtnText!=NULL && (HFONT)m_fontActiveTabBtnText!=NULL);
|
|
}
|
|
|
|
COXTabViewContainer::~COXTabViewContainer()
|
|
{
|
|
}
|
|
|
|
BEGIN_MESSAGE_MAP(COXTabViewContainer, CWnd)
|
|
//{{AFX_MSG_MAP(COXTabViewContainer)
|
|
ON_WM_SIZE()
|
|
ON_WM_PAINT()
|
|
ON_WM_MOUSEMOVE()
|
|
ON_WM_LBUTTONDOWN()
|
|
ON_WM_LBUTTONUP()
|
|
ON_WM_TIMER()
|
|
ON_WM_SETCURSOR()
|
|
ON_WM_ERASEBKGND()
|
|
ON_WM_CANCELMODE()
|
|
ON_WM_DESTROY()
|
|
ON_WM_HSCROLL()
|
|
ON_WM_VSCROLL()
|
|
ON_WM_SETTINGCHANGE()
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL COXTabViewContainer::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName,
|
|
DWORD dwStyle, const RECT& rect,
|
|
CWnd* pParentWnd, UINT nID,
|
|
CCreateContext* pContext/*=NULL*/)
|
|
{
|
|
UNREFERENCED_PARAMETER(lpszClassName);
|
|
UNREFERENCED_PARAMETER(lpszWindowName);
|
|
UNREFERENCED_PARAMETER(pContext);
|
|
return Create(pParentWnd,rect,dwStyle,nID);
|
|
}
|
|
|
|
|
|
BOOL COXTabViewContainer::Create(CWnd* pParentWnd, CRect rect/*=CRect(0,0,0,0)*/,
|
|
DWORD dwStyle/*=WS_CHILD|WS_VISIBLE*/,
|
|
UINT nID/*=AFX_IDW_PANE_FIRST*/)
|
|
{
|
|
ASSERT(pParentWnd != NULL);
|
|
ASSERT(dwStyle & WS_CHILD);
|
|
ASSERT(nID != 0);
|
|
|
|
// the Windows scroll bar styles bits turn on the smart scrollbars
|
|
DWORD dwCreateStyle=dwStyle&~(WS_HSCROLL|WS_VSCROLL);
|
|
dwCreateStyle&=~WS_BORDER;
|
|
|
|
dwCreateStyle|=WS_CHILD;
|
|
|
|
// define our own window class
|
|
WNDCLASS wndClass;
|
|
wndClass.style=CS_DBLCLKS;
|
|
wndClass.lpfnWndProc=AfxWndProc;
|
|
wndClass.cbClsExtra=0;
|
|
wndClass.cbWndExtra=0;
|
|
wndClass.hInstance=AfxGetInstanceHandle();
|
|
wndClass.hIcon=0;
|
|
wndClass.hCursor=::LoadCursor(NULL,IDC_ARROW);
|
|
wndClass.hbrBackground=(HBRUSH)(COLOR_BTNFACE+1);
|
|
wndClass.lpszMenuName=NULL;
|
|
wndClass.lpszClassName=_T("TabViewContainer");
|
|
|
|
if(!AfxRegisterClass(&wndClass))
|
|
return FALSE;
|
|
|
|
if (!CreateEx(WS_EX_CLIENTEDGE,wndClass.lpszClassName,NULL,
|
|
dwCreateStyle,rect.left,rect.top,rect.Width(),rect.Height(),
|
|
pParentWnd->m_hWnd,(HMENU)(INT_PTR)nID,NULL))
|
|
{
|
|
return FALSE; // create invisible
|
|
}
|
|
|
|
// remove WS_EX_CLIENTEDGE style from parent window
|
|
pParentWnd->ModifyStyleEx(WS_EX_CLIENTEDGE, 0, SWP_DRAWFRAME);
|
|
|
|
// sign
|
|
::SetWindowLongPtr(GetSafeHwnd(),GWL_USERDATA,ID_TABVIEWCONTAINER_SIGN);
|
|
|
|
SetScrollStyle(0,TRUE);
|
|
|
|
CalcLayout();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// COXTabViewContainer command routing
|
|
|
|
BOOL COXTabViewContainer::OnCommand(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (CWnd::OnCommand(wParam,lParam))
|
|
return TRUE;
|
|
|
|
// route commands from the container to the parent frame window
|
|
if(GetParentFrame()!=NULL)
|
|
return (BOOL)GetParentFrame()->SendMessage(WM_COMMAND,wParam,lParam);
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL COXTabViewContainer::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
|
|
{
|
|
if (CWnd::OnNotify(wParam,lParam,pResult))
|
|
return TRUE;
|
|
|
|
// route commands from the container to the parent frame window
|
|
|
|
if(GetParentFrame()!=NULL)
|
|
{
|
|
*pResult=GetParentFrame()->SendMessage(WM_NOTIFY,wParam,lParam);
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
*pResult=0;
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
void COXTabViewContainer::OnDestroy()
|
|
{
|
|
if(m_nScrollPageTimer!=-1)
|
|
{
|
|
KillTimer(m_nScrollPageTimer);
|
|
m_nScrollPageTimer=-1;
|
|
}
|
|
|
|
CWnd::OnDestroy();
|
|
}
|
|
|
|
|
|
void COXTabViewContainer::OnSize(UINT nType, int cx, int cy)
|
|
{
|
|
CWnd::OnSize(nType, cx, cy);
|
|
|
|
// TODO: Add your message handler code here
|
|
if(nType!=SIZE_MINIMIZED && cx>0 && cy>0)
|
|
{
|
|
CalcLayout();
|
|
|
|
UpdateScrollSizes();
|
|
|
|
CWnd* pWnd=GetActivePage();
|
|
if(pWnd!=NULL)
|
|
{
|
|
ASSERT(::IsWindow(pWnd->m_hWnd));
|
|
if(::IsWindow(pWnd->m_hWnd))
|
|
pWnd->MoveWindow(m_rectPage);
|
|
}
|
|
|
|
RedrawContainer();
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void COXTabViewContainer::OnPaint()
|
|
{
|
|
CPaintDC dc(this); // device context for painting
|
|
|
|
// TODO: Add your message handler code here
|
|
|
|
CWnd* pWnd=GetActivePage();
|
|
if(pWnd!=NULL)
|
|
{
|
|
CRect rect;
|
|
pWnd->GetWindowRect(rect);
|
|
ScreenToClient(rect);
|
|
if(m_rectPage!=rect && !rect.IsRectEmpty())
|
|
{
|
|
CRgn rgnInTheory;
|
|
CRgn rgnInReality;
|
|
if(rgnInTheory.CreateRectRgnIndirect(m_rectPage) &&
|
|
rgnInReality.CreateRectRgnIndirect(rect))
|
|
{
|
|
if(rgnInTheory.CombineRgn(&rgnInTheory,&rgnInReality,
|
|
RGN_DIFF)!=ERROR)
|
|
{
|
|
CBrush* pBrush=NULL;
|
|
CBrush brush;
|
|
HBRUSH hBrush=(HBRUSH)(INT_PTR)::GetClassLongPtr(pWnd->m_hWnd,
|
|
GCL_HBRBACKGROUND);
|
|
if(hBrush==NULL)
|
|
{
|
|
if(brush.CreateSolidBrush(::GetSysColor(COLOR_WINDOW)))
|
|
pBrush=&brush;
|
|
else
|
|
pBrush=dc.GetCurrentBrush();
|
|
}
|
|
else
|
|
{
|
|
pBrush=CBrush::FromHandle(hBrush);
|
|
}
|
|
|
|
if(pBrush!=NULL)
|
|
dc.FillRgn(&rgnInTheory,pBrush);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
DrawScrollButtons(&dc);
|
|
DrawSplitter(&dc);
|
|
DrawSizeBar(&dc);
|
|
DrawTabBtnArea(&dc);
|
|
|
|
// Do not call CWnd::OnPaint() for painting messages
|
|
}
|
|
|
|
|
|
void COXTabViewContainer::OnMouseMove(UINT nFlags, CPoint point)
|
|
{
|
|
// TODO: Add your message handler code here and/or call default
|
|
|
|
if(m_nPressedScrlBtn!=NONE)
|
|
{
|
|
int hitTest=HitTest(point);
|
|
// send corresponding messages
|
|
if(((int)m_nPressedScrlBtn==hitTest && !m_bIsScrlBtnPressed) ||
|
|
((int)m_nPressedScrlBtn!=hitTest && m_bIsScrlBtnPressed))
|
|
{
|
|
m_bIsScrlBtnPressed=!m_bIsScrlBtnPressed;
|
|
RedrawScrollButton(m_nPressedScrlBtn);
|
|
}
|
|
}
|
|
else if(m_bIsSplitterPressed)
|
|
{
|
|
CPoint ptMoved=point;
|
|
if(ptMoved.x>m_rectPage.right-ID_MINSCROLLBARWIDTH+ID_SPLITTERWIDTH/2)
|
|
ptMoved.x=m_rectPage.right-ID_MINSCROLLBARWIDTH+ID_SPLITTERWIDTH/2;
|
|
if(ptMoved.x<m_rectScrollToEndBtn.right+ID_SPLITTERWIDTH/2)
|
|
ptMoved.x=m_rectScrollToEndBtn.right+ID_SPLITTERWIDTH/2;
|
|
|
|
int nOldSplitterLeft=m_rectSplitter.left;
|
|
m_rectSplitter.left=ptMoved.x-ID_SPLITTERWIDTH/2;
|
|
if(nOldSplitterLeft!=m_rectSplitter.left)
|
|
{
|
|
m_rectSplitter.right=m_rectSplitter.left+ID_SPLITTERWIDTH;
|
|
m_rectScrollBarHorz.left=m_rectSplitter.right;
|
|
|
|
m_nLastTabBtnAreaWidth=m_rectSplitter.left-m_rectScrollToEndBtn.right;
|
|
|
|
m_rectTabBtnArea.right+=m_rectSplitter.left-nOldSplitterLeft;
|
|
if(m_rectTabBtnArea.right<m_rectTabBtnArea.left)
|
|
m_rectTabBtnArea.right=m_rectTabBtnArea.left;
|
|
|
|
if(::IsWindow(m_scrlBarHorz.GetSafeHwnd()))
|
|
m_scrlBarHorz.MoveWindow(m_rectScrollBarHorz);
|
|
RedrawSplitter();
|
|
|
|
if(nOldSplitterLeft<m_rectSplitter.left)
|
|
{
|
|
CRect rect=m_rectSplitter;
|
|
rect.left=nOldSplitterLeft;
|
|
rect.right=m_rectSplitter.left;
|
|
RedrawWindow(rect);
|
|
|
|
if(m_nTabBtnAreaOrigin<0)
|
|
{
|
|
ASSERT(GetPageCount()==m_arrTabBtnRects.GetSize());
|
|
rect=m_arrTabBtnRects[GetPageCount()-1];
|
|
rect+=m_rectTabBtnArea.TopLeft();
|
|
if(rect.right+m_nTabBtnAreaOrigin<=m_rectTabBtnArea.right)
|
|
{
|
|
m_nTabBtnAreaOrigin+=
|
|
m_rectSplitter.left-nOldSplitterLeft;
|
|
m_nTabBtnAreaOrigin=
|
|
m_nTabBtnAreaOrigin>0 ? 0 : m_nTabBtnAreaOrigin;
|
|
RedrawTabBtnArea();
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
CWnd::OnMouseMove(nFlags, point);
|
|
}
|
|
|
|
|
|
void COXTabViewContainer::OnLButtonDown(UINT nFlags, CPoint point)
|
|
{
|
|
// TODO: Add your message handler code here and/or call default
|
|
|
|
CWnd::OnLButtonDown(nFlags, point);
|
|
|
|
int hitTest=HitTest(point);
|
|
if(hitTest>=0 && hitTest<GetPageCount() && hitTest!=GetActivePageIndex())
|
|
SetActivePageIndex(hitTest);
|
|
else
|
|
StartTracking(point);
|
|
}
|
|
|
|
|
|
void COXTabViewContainer::OnLButtonUp(UINT nFlags, CPoint point)
|
|
{
|
|
// TODO: Add your message handler code here and/or call default
|
|
|
|
StopTracking(point);
|
|
|
|
CWnd::OnLButtonUp(nFlags,point);
|
|
}
|
|
|
|
|
|
void COXTabViewContainer::OnTimer(UINT nIDEvent)
|
|
{
|
|
// TODO: Add your message handler code here and/or call default
|
|
|
|
if((int)nIDEvent==m_nScrollPageTimer)
|
|
{
|
|
if(m_nPressedScrlBtn!=NONE && m_bIsScrlBtnPressed)
|
|
ScrollPage(m_nPressedScrlBtn);
|
|
}
|
|
|
|
CWnd::OnTimer(nIDEvent);
|
|
}
|
|
|
|
|
|
BOOL COXTabViewContainer::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
|
|
{
|
|
// TODO: Add your message handler code here and/or call default
|
|
|
|
CPoint point;
|
|
::GetCursorPos(&point);
|
|
ScreenToClient(&point);
|
|
int hitTest=HitTest(point);
|
|
if(m_bIsSplitterPressed || hitTest==SPLITTER)
|
|
{
|
|
HCURSOR hCursor=AfxGetApp()->
|
|
LoadCursor(MAKEINTRESOURCE(AFX_IDC_HSPLITBAR));
|
|
if(hCursor==NULL)
|
|
hCursor=::LoadCursor(NULL,IDC_SIZEWE);
|
|
SetCursor(hCursor);
|
|
return TRUE;
|
|
}
|
|
|
|
return CWnd::OnSetCursor(pWnd, nHitTest, message);
|
|
}
|
|
|
|
|
|
BOOL COXTabViewContainer::OnEraseBkgnd(CDC* pDC)
|
|
{
|
|
// TODO: Add your message handler code here and/or call default
|
|
|
|
if(GetPageCount()==0)
|
|
{
|
|
CRect rect;
|
|
pDC->GetClipBox(rect);
|
|
pDC->FillSolidRect(rect,::GetSysColor(COLOR_BTNFACE));
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void COXTabViewContainer::OnCancelMode()
|
|
{
|
|
CWnd::OnCancelMode();
|
|
|
|
// TODO: Add your message handler code here
|
|
|
|
CPoint point;
|
|
::GetCursorPos(&point);
|
|
ScreenToClient(&point);
|
|
StopTracking(point);
|
|
}
|
|
|
|
|
|
void COXTabViewContainer::OnHScroll(UINT nSBCode, UINT nPos,
|
|
CScrollBar* pScrollBar)
|
|
{
|
|
// TODO: Add your message handler code here and/or call default
|
|
|
|
ASSERT(pScrollBar==GetHorzScrollBar());
|
|
|
|
CWnd* pWnd=GetActivePage();
|
|
ASSERT(pWnd!=NULL);
|
|
if(pWnd!=NULL)
|
|
{
|
|
ASSERT(::IsWindow(pWnd->m_hWnd));
|
|
pWnd->SendMessage(WM_HSCROLL,MAKEWPARAM(nSBCode,nPos),
|
|
(LPARAM)pScrollBar->m_hWnd);
|
|
}
|
|
}
|
|
|
|
void COXTabViewContainer::OnVScroll(UINT nSBCode, UINT nPos,
|
|
CScrollBar* pScrollBar)
|
|
{
|
|
// TODO: Add your message handler code here and/or call default
|
|
|
|
ASSERT(pScrollBar==GetVertScrollBar());
|
|
|
|
CWnd* pWnd=GetActivePage();
|
|
ASSERT(pWnd!=NULL);
|
|
if(pWnd!=NULL)
|
|
{
|
|
ASSERT(::IsWindow(pWnd->m_hWnd));
|
|
pWnd->SendMessage(WM_VSCROLL,MAKEWPARAM(nSBCode,nPos),
|
|
(LPARAM)pScrollBar->m_hWnd);
|
|
}
|
|
}
|
|
|
|
void COXTabViewContainer::OnSettingChange(UINT uFlags, LPCTSTR lpszSection)
|
|
{
|
|
UNREFERENCED_PARAMETER(uFlags);
|
|
UNREFERENCED_PARAMETER(lpszSection);
|
|
|
|
CalcLayout();
|
|
|
|
UpdateScrollSizes();
|
|
|
|
CWnd* pWnd=GetActivePage();
|
|
if(pWnd!=NULL)
|
|
{
|
|
ASSERT(::IsWindow(pWnd->m_hWnd));
|
|
if(::IsWindow(pWnd->m_hWnd))
|
|
pWnd->MoveWindow(m_rectPage);
|
|
}
|
|
|
|
RedrawContainer();
|
|
|
|
CWnd::OnSettingChange(uFlags, lpszSection);
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
BOOL COXTabViewContainer::SaveState(LPCTSTR lpszProfileName)
|
|
{
|
|
CWinApp* pApp=AfxGetApp();
|
|
if(pApp==NULL)
|
|
return FALSE;
|
|
|
|
BOOL bResult=TRUE;
|
|
bResult&=pApp->WriteProfileInt(lpszProfileName,
|
|
_T("TabButtonsAreaWidth"),m_nLastTabBtnAreaWidth);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
BOOL COXTabViewContainer::LoadState(LPCTSTR lpszProfileName)
|
|
{
|
|
CWinApp* pApp=AfxGetApp();
|
|
if(pApp==NULL)
|
|
return FALSE;
|
|
|
|
m_nLastTabBtnAreaWidth=pApp->GetProfileInt(lpszProfileName,
|
|
_T("TabButtonsAreaWidth"),m_nLastTabBtnAreaWidth);
|
|
|
|
CalcLayout();
|
|
UpdateScrollSizes();
|
|
RedrawContainer();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL COXTabViewContainer::InsertPage(int nIndex,
|
|
CRuntimeClass* pClass,
|
|
CCreateContext* pContext,
|
|
LPCTSTR lpszTitle/*=NULL*/)
|
|
{
|
|
ASSERT_VALID(this);
|
|
ASSERT(nIndex>=0 && nIndex<=GetPageCount());
|
|
ASSERT(pClass!=NULL);
|
|
ASSERT(pClass->IsDerivedFrom(RUNTIME_CLASS(CWnd)));
|
|
ASSERT(AfxIsValidAddress(pClass,sizeof(CRuntimeClass),FALSE));
|
|
|
|
if(!(nIndex>=0 && nIndex<=GetPageCount()) || pClass==NULL)
|
|
return FALSE;
|
|
|
|
CCreateContext context;
|
|
if(pContext==NULL)
|
|
{
|
|
// if no context specified, generate one from the currently active
|
|
// view if possible
|
|
CView* pOldView=(CView*)GetActivePage();
|
|
if(pOldView!=NULL && pOldView->IsKindOf(RUNTIME_CLASS(CView)))
|
|
{
|
|
// set info about last pane
|
|
ASSERT(context.m_pCurrentFrame==NULL);
|
|
context.m_pLastView=pOldView;
|
|
context.m_pCurrentDoc=pOldView->GetDocument();
|
|
if(context.m_pCurrentDoc!=NULL)
|
|
{
|
|
context.m_pNewDocTemplate=context.m_pCurrentDoc->
|
|
GetDocTemplate();
|
|
}
|
|
}
|
|
pContext=&context;
|
|
}
|
|
|
|
CWnd* pWnd;
|
|
TRY
|
|
{
|
|
pWnd=(CWnd*)pClass->CreateObject();
|
|
if(pWnd==NULL)
|
|
AfxThrowMemoryException();
|
|
}
|
|
CATCH_ALL(e)
|
|
{
|
|
TRACE(_T("COXTabViewContainer::InsertPage: Out of memory inserting new page\n"));
|
|
// Note: DELETE_EXCEPTION(e) not required
|
|
return FALSE;
|
|
}
|
|
END_CATCH_ALL
|
|
|
|
ASSERT_KINDOF(CWnd,pWnd);
|
|
ASSERT(pWnd->m_hWnd==NULL); // not yet created
|
|
|
|
DWORD dwStyle=AFX_WS_DEFAULT_VIEW;
|
|
#if _MFC_VER < 0x0700
|
|
if(afxData.bWin4)
|
|
#endif
|
|
dwStyle&=~WS_BORDER;
|
|
|
|
DWORD dwID=GetUniqueId();
|
|
|
|
// Create with the right size
|
|
if(!pWnd->Create(NULL,NULL,dwStyle,m_rectPage,this,dwID,pContext))
|
|
{
|
|
TRACE(_T("COXTabViewContainer::InsertPage: couldn't create new page\n"));
|
|
// pWnd will be cleaned up by PostNcDestroy
|
|
return FALSE;
|
|
}
|
|
|
|
if(InsertPage(nIndex,pWnd,lpszTitle))
|
|
{
|
|
CWnd* pWnd=GetPage(nIndex);
|
|
ASSERT(pWnd!=NULL);
|
|
ASSERT(::IsWindow(pWnd->m_hWnd));
|
|
if(pWnd->IsKindOf(RUNTIME_CLASS(CView)))
|
|
{
|
|
// send initial notification message
|
|
pWnd->SendMessage(WM_INITIALUPDATE);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL COXTabViewContainer::InsertPage(int nIndex, CWnd* pWnd,
|
|
LPCTSTR lpszTitle/*=NULL*/)
|
|
{
|
|
ASSERT_VALID(this);
|
|
ASSERT(nIndex>=0 && nIndex<=GetPageCount());
|
|
ASSERT(pWnd!=NULL);
|
|
ASSERT(::IsWindow(pWnd->m_hWnd));
|
|
|
|
if(!(nIndex>=0 && nIndex<=GetPageCount())
|
|
|| pWnd==NULL || !::IsWindow(pWnd->m_hWnd))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// set this container as parent window of the specified page
|
|
pWnd->SetParent(this);
|
|
|
|
PAGEINFO pi;
|
|
pi.pWnd=pWnd;
|
|
if(lpszTitle==NULL)
|
|
{
|
|
pWnd->GetWindowText(pi.sTitle);
|
|
if(pi.sTitle.IsEmpty())
|
|
{
|
|
pi.sTitle.Format(_T("%d"),nIndex);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pi.sTitle=lpszTitle;
|
|
}
|
|
|
|
m_arrPages.InsertAt(nIndex,pi);
|
|
|
|
CalcTabBtnRects();
|
|
|
|
SetActivePageIndex(nIndex);
|
|
|
|
RedrawContainer();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL COXTabViewContainer::DeletePage(CWnd* pWnd,
|
|
BOOL bDestroy/*=TRUE*/)
|
|
{
|
|
ASSERT(pWnd!=NULL);
|
|
ASSERT(IsPage(pWnd));
|
|
int nIndex=-1;
|
|
if(FindPage(pWnd,nIndex))
|
|
{
|
|
return DeletePage(nIndex,bDestroy);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL COXTabViewContainer::DeletePage(int nIndex,
|
|
BOOL bDestroy/*=TRUE*/)
|
|
{
|
|
ASSERT_VALID(this);
|
|
ASSERT(nIndex>=0 && nIndex<GetPageCount());
|
|
|
|
if(nIndex>=0 && nIndex<GetPageCount())
|
|
{
|
|
// if active page is being deleted - activate next
|
|
int nActivePage=GetActivePageIndex();
|
|
if(nActivePage==nIndex)
|
|
{
|
|
if(nActivePage==GetPageCount()-1)
|
|
SetActivePageIndex(0);
|
|
else
|
|
SetActivePageIndex(GetPageCount()>1 ? nActivePage+1 : 0);
|
|
}
|
|
CWnd* pWnd=GetPage(nIndex);
|
|
ASSERT(pWnd!=NULL);
|
|
m_arrUniqueIDs.Add(pWnd->GetDlgCtrlID());
|
|
if(bDestroy && ::IsWindow(pWnd->m_hWnd))
|
|
VERIFY(pWnd->DestroyWindow());
|
|
|
|
m_arrPages.RemoveAt(nIndex);
|
|
|
|
nActivePage=GetActivePageIndex();
|
|
if(nActivePage>=nIndex)
|
|
m_nActivePageIndex--;
|
|
|
|
CalcTabBtnRects();
|
|
|
|
RedrawContainer();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL COXTabViewContainer::SetPageTitle(int nIndex, LPCTSTR lpszTitle)
|
|
{
|
|
ASSERT(nIndex>=0 && nIndex<GetPageCount());
|
|
|
|
if(nIndex>=0 && nIndex<GetPageCount())
|
|
{
|
|
PAGEINFO& pi=m_arrPages[nIndex];
|
|
if(pi.sTitle.Compare(lpszTitle)!=0)
|
|
{
|
|
pi.sTitle=lpszTitle;
|
|
CalcTabBtnRects();
|
|
CRect rect=m_arrTabBtnRects[nIndex];
|
|
if(rect.left<m_rectTabBtnArea.right &&
|
|
rect.right>m_rectTabBtnArea.right)
|
|
{
|
|
RedrawTabBtnArea();
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL COXTabViewContainer::SetActivePageIndex(int nIndex)
|
|
{
|
|
if(nIndex==m_nActivePageIndex)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
CWnd* pWndOld=GetActivePage();
|
|
if(pWndOld!=NULL)
|
|
{
|
|
ASSERT(::IsWindow(pWndOld->m_hWnd));
|
|
if(::IsWindow(pWndOld->m_hWnd))
|
|
{
|
|
UpdateScrollInfo();
|
|
|
|
pWndOld->ShowWindow(SW_HIDE);
|
|
PAGEINFO pi=m_arrPages[GetActivePageIndex()];
|
|
m_nActivePageIndex=-1;
|
|
UINT nBar=(pi.bHasScrollHorz&pi.bHasScrollVert ? SB_BOTH :
|
|
(pi.bHasScrollHorz ? SB_HORZ :
|
|
(pi.bHasScrollVert ? SB_VERT : 0)));
|
|
if(nBar!=0)
|
|
{
|
|
pWndOld->ShowScrollBar(nBar,TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
m_nActivePageIndex=nIndex;
|
|
if(m_nActivePageIndex>=0 && m_nActivePageIndex<GetPageCount())
|
|
{
|
|
EnsureTabBtnVisible(m_nActivePageIndex);
|
|
|
|
CWnd* pWnd=GetPage(m_nActivePageIndex);
|
|
if(pWnd!=NULL)
|
|
{
|
|
ASSERT(::IsWindow(pWnd->m_hWnd));
|
|
if(::IsWindow(pWnd->m_hWnd))
|
|
{
|
|
IniScrollInfo();
|
|
|
|
pWnd->ShowWindow(SW_SHOW);
|
|
CRect rect;
|
|
pWnd->GetWindowRect(rect);
|
|
if(rect.Width()!=m_rectPage.Width() ||
|
|
rect.Height()!=m_rectPage.Height())
|
|
{
|
|
pWnd->MoveWindow(m_rectPage);
|
|
}
|
|
else
|
|
{
|
|
pWnd->SendMessage(WM_SIZE,SIZE_RESTORED,
|
|
MAKELPARAM(rect.Width(),rect.Height()));
|
|
}
|
|
|
|
// set the focus to the page
|
|
CFrameWnd* pFrameWnd=(CFrameWnd*)GetParent();
|
|
ASSERT(pFrameWnd!=NULL);
|
|
if(pFrameWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd)))
|
|
{
|
|
if(pWnd->IsKindOf(RUNTIME_CLASS(CView)))
|
|
{
|
|
pFrameWnd->SetActiveView((CView*)pWnd);
|
|
}
|
|
else
|
|
{
|
|
if(pWndOld!=NULL &&
|
|
pWndOld->IsKindOf(RUNTIME_CLASS(CView)))
|
|
{
|
|
pFrameWnd->SetActiveView(NULL);
|
|
}
|
|
pWnd->SetFocus();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pWnd->SetFocus();
|
|
}
|
|
|
|
RedrawTabBtnArea();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void COXTabViewContainer::SetScrollStyle(DWORD dwScrollStyle,
|
|
BOOL bForceToRebuild/*=FALSE*/)
|
|
{
|
|
ASSERT(::IsWindow(GetSafeHwnd()));
|
|
|
|
if(!bForceToRebuild &&
|
|
m_dwScrollStyle==(dwScrollStyle & (WS_VSCROLL | WS_HSCROLL)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_dwScrollStyle=(dwScrollStyle & (WS_VSCROLL | WS_HSCROLL));
|
|
|
|
if(::IsWindow(m_scrlBarHorz.GetSafeHwnd()))
|
|
{
|
|
m_scrlBarHorz.DestroyWindow();
|
|
}
|
|
if(::IsWindow(m_scrlBarVert.GetSafeHwnd()))
|
|
{
|
|
m_scrlBarVert.DestroyWindow();
|
|
}
|
|
|
|
VERIFY(m_scrlBarHorz.Create(SBS_HORZ|WS_CHILD|WS_VISIBLE|
|
|
((dwScrollStyle & WS_HSCROLL) ? 0 : WS_DISABLED),
|
|
m_rectScrollBarHorz,this,AFX_IDW_HSCROLL_FIRST));
|
|
VERIFY(m_scrlBarVert.Create(SBS_VERT|WS_CHILD|WS_VISIBLE|
|
|
((dwScrollStyle & WS_VSCROLL) ? 0 : WS_DISABLED),
|
|
m_rectScrollBarVert,this,AFX_IDW_VSCROLL_FIRST));
|
|
}
|
|
|
|
void COXTabViewContainer::CalcLayout()
|
|
{
|
|
ASSERT(::IsWindow(GetSafeHwnd()));
|
|
|
|
EmptyRects();
|
|
|
|
CRect rect;
|
|
GetClientRect(rect);
|
|
|
|
if(rect.IsRectEmpty())
|
|
return;
|
|
|
|
CSize szScrollBtn=CSize(::GetSystemMetrics(SM_CXHSCROLL),
|
|
::GetSystemMetrics(SM_CYHSCROLL));
|
|
|
|
// scroll buttons
|
|
//
|
|
m_rectScrollToStartBtn=CRect(rect.left,rect.bottom-szScrollBtn.cy,
|
|
rect.left+szScrollBtn.cx,rect.bottom);
|
|
|
|
m_rectScrollBackwardBtn=m_rectScrollToStartBtn;
|
|
m_rectScrollBackwardBtn.OffsetRect(m_rectScrollToStartBtn.Width(),0);
|
|
|
|
m_rectScrollForwardBtn=m_rectScrollBackwardBtn;
|
|
m_rectScrollForwardBtn.OffsetRect(m_rectScrollBackwardBtn.Width(),0);
|
|
|
|
m_rectScrollToEndBtn=m_rectScrollForwardBtn;
|
|
m_rectScrollToEndBtn.OffsetRect(m_rectScrollForwardBtn.Width(),0);
|
|
//
|
|
/////////////////////////////////////////////
|
|
|
|
// page rect
|
|
m_rectPage=rect;
|
|
m_rectPage.right-=szScrollBtn.cx;
|
|
m_rectPage.bottom-=szScrollBtn.cy;
|
|
|
|
int nTabBtnAreaWidth=m_nLastTabBtnAreaWidth;
|
|
if(m_rectPage.right<m_rectScrollToEndBtn.right+
|
|
nTabBtnAreaWidth+ID_MINSCROLLBARWIDTH)
|
|
{
|
|
nTabBtnAreaWidth=m_rectPage.right-
|
|
m_rectScrollToEndBtn.right-ID_MINSCROLLBARWIDTH;
|
|
}
|
|
|
|
// tab buttons area
|
|
m_rectTabBtnArea=m_rectScrollToStartBtn;
|
|
m_rectTabBtnArea.left=m_rectScrollToEndBtn.right;
|
|
m_rectTabBtnArea.right=m_rectTabBtnArea.left+nTabBtnAreaWidth;
|
|
if(m_rectTabBtnArea.right<m_rectTabBtnArea.left)
|
|
m_rectTabBtnArea.right=m_rectTabBtnArea.left;
|
|
|
|
// splitter rect
|
|
m_rectSplitter=m_rectScrollToStartBtn;
|
|
m_rectSplitter.left=m_rectTabBtnArea.right;
|
|
m_rectSplitter.right=m_rectSplitter.left+ID_SPLITTERWIDTH;
|
|
|
|
// horz scroll bar
|
|
m_rectScrollBarHorz=m_rectScrollToStartBtn;
|
|
m_rectScrollBarHorz.left=m_rectSplitter.right;
|
|
m_rectScrollBarHorz.right=m_rectPage.right;
|
|
|
|
// vert scroll bar
|
|
m_rectScrollBarVert=m_rectPage;
|
|
m_rectScrollBarVert.left=m_rectPage.right;
|
|
m_rectScrollBarVert.right=rect.right;
|
|
|
|
// size bar
|
|
m_rectSizeBar=rect;
|
|
m_rectSizeBar.top=m_rectScrollBarVert.bottom;
|
|
m_rectSizeBar.left=m_rectScrollBarHorz.right;
|
|
|
|
}
|
|
|
|
void COXTabViewContainer::CalcTabBtnRects()
|
|
{
|
|
m_arrTabBtnRects.RemoveAll();
|
|
|
|
CString sTitle;
|
|
int nLeftSide=0;
|
|
CRect rect;
|
|
|
|
CClientDC dc(this);
|
|
ASSERT((HFONT)m_fontActiveTabBtnText!=NULL);
|
|
if((HFONT)m_fontActiveTabBtnText!=NULL)
|
|
dc.SelectObject(&m_fontActiveTabBtnText);
|
|
|
|
for(int nIndex=0; nIndex<GetPageCount(); nIndex++)
|
|
{
|
|
rect=m_rectTabBtnArea;
|
|
rect-=rect.TopLeft();
|
|
rect.right=0xffff;
|
|
|
|
sTitle=GetPageTitle(nIndex);
|
|
|
|
dc.DrawText(sTitle,rect,DT_CALCRECT|DT_LEFT|DT_SINGLELINE|DT_VCENTER);
|
|
rect.OffsetRect(nLeftSide,0);
|
|
rect.right+=2*ID_TABBTNOVERLAPSIZE+2*ID_TABBTNGAPSIZE;
|
|
|
|
m_arrTabBtnRects.Add(rect);
|
|
|
|
nLeftSide=rect.right-ID_TABBTNOVERLAPSIZE;
|
|
}
|
|
}
|
|
|
|
void COXTabViewContainer::EmptyRects()
|
|
{
|
|
m_rectScrollForwardBtn.SetRectEmpty();
|
|
m_rectScrollBackwardBtn.SetRectEmpty();
|
|
m_rectScrollToStartBtn.SetRectEmpty();
|
|
m_rectScrollToEndBtn.SetRectEmpty();
|
|
|
|
m_rectTabBtnArea.SetRectEmpty();
|
|
|
|
m_rectScrollBarHorz.SetRectEmpty();
|
|
m_rectScrollBarVert.SetRectEmpty();
|
|
|
|
m_rectSplitter.SetRectEmpty();
|
|
|
|
m_rectSizeBar.SetRectEmpty();
|
|
|
|
m_rectPage.SetRectEmpty();
|
|
}
|
|
|
|
void COXTabViewContainer::UpdateScrollSizes()
|
|
{
|
|
if(::IsWindow(m_scrlBarHorz.GetSafeHwnd()))
|
|
{
|
|
m_scrlBarHorz.MoveWindow(m_rectScrollBarHorz);
|
|
}
|
|
if(::IsWindow(m_scrlBarVert.GetSafeHwnd()))
|
|
{
|
|
m_scrlBarVert.MoveWindow(m_rectScrollBarVert);
|
|
}
|
|
}
|
|
|
|
|
|
void COXTabViewContainer::IniScrollInfo()
|
|
{
|
|
CWnd* pWnd=GetActivePage();
|
|
if(pWnd==NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
PAGEINFO& pi=m_arrPages[GetActivePageIndex()];
|
|
|
|
pi.bHasScrollHorz=((pWnd->GetStyle()&WS_HSCROLL)==WS_HSCROLL);
|
|
pi.bHasScrollVert=((pWnd->GetStyle()&WS_VSCROLL)==WS_VSCROLL);
|
|
|
|
if(pi.bHasScrollHorz)
|
|
{
|
|
pi.GetScrollInfo(pWnd,TRUE);
|
|
}
|
|
if(pi.bHasScrollVert)
|
|
{
|
|
pi.GetScrollInfo(pWnd,FALSE);
|
|
}
|
|
|
|
DWORD dwStyle=(pi.bHasScrollHorz ? WS_HSCROLL : 0) |
|
|
(pi.bHasScrollVert ? WS_VSCROLL : 0);
|
|
SetScrollStyle(dwStyle,TRUE);
|
|
pWnd->ShowScrollBar(SB_BOTH,FALSE);
|
|
pWnd->RedrawWindow();
|
|
|
|
if(pi.bHasScrollHorz ||
|
|
(pi.scrlInfoHorz.nMax>0 && pi.scrlInfoHorz.nPage>0 &&
|
|
pi.scrlInfoHorz.nPos>0 && pi.scrlInfoHorz.nPos<=pi.scrlInfoHorz.nMax))
|
|
{
|
|
ASSERT(::IsWindow(m_scrlBarHorz.GetSafeHwnd()));
|
|
m_scrlBarHorz.SetScrollInfo(&pi.scrlInfoHorz);
|
|
}
|
|
if(pi.bHasScrollVert ||
|
|
(pi.scrlInfoVert.nMax>0 && pi.scrlInfoVert.nPage>0 &&
|
|
pi.scrlInfoVert.nPos>0 && pi.scrlInfoVert.nPos<=pi.scrlInfoVert.nMax))
|
|
{
|
|
ASSERT(::IsWindow(m_scrlBarVert.GetSafeHwnd()));
|
|
m_scrlBarVert.SetScrollInfo(&pi.scrlInfoVert);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
static BOOL g_bUpdatingScrollInfo=FALSE;
|
|
static BOOL g_bUpdatingScrollState=FALSE;
|
|
|
|
void COXTabViewContainer::UpdateScrollInfo()
|
|
{
|
|
if(g_bUpdatingScrollInfo || g_bUpdatingScrollState)
|
|
{
|
|
return;
|
|
}
|
|
|
|
g_bUpdatingScrollInfo=TRUE;
|
|
|
|
CWnd* pWnd=GetActivePage();
|
|
if(pWnd==NULL || !pWnd->IsWindowVisible())
|
|
{
|
|
g_bUpdatingScrollInfo=FALSE;
|
|
return;
|
|
}
|
|
|
|
PAGEINFO& pi=m_arrPages[GetActivePageIndex()];
|
|
|
|
if(pi.bHasScrollHorz)
|
|
{
|
|
pWnd->ModifyStyle(WS_VISIBLE,NULL);
|
|
pWnd->ShowScrollBar(SB_HORZ,TRUE);
|
|
pWnd->ModifyStyle(NULL,WS_HSCROLL,SWP_DRAWFRAME);
|
|
|
|
pi.GetScrollInfo(pWnd,TRUE);
|
|
|
|
ASSERT(::IsWindow(m_scrlBarHorz.GetSafeHwnd()));
|
|
m_scrlBarHorz.SetScrollInfo(&pi.scrlInfoHorz);
|
|
|
|
pWnd->ShowScrollBar(SB_HORZ,FALSE);
|
|
pWnd->ModifyStyle(WS_HSCROLL,NULL,SWP_DRAWFRAME);
|
|
pWnd->ModifyStyle(NULL,WS_VISIBLE);
|
|
}
|
|
else
|
|
{
|
|
pi.scrlInfoHorz.cbSize=sizeof(SCROLLINFO);
|
|
pWnd->GetScrollInfo(SB_HORZ,&pi.scrlInfoHorz);
|
|
}
|
|
|
|
if(pi.bHasScrollVert)
|
|
{
|
|
pWnd->ModifyStyle(WS_VISIBLE,NULL);
|
|
pWnd->ShowScrollBar(SB_VERT,TRUE);
|
|
pWnd->ModifyStyle(NULL,WS_VSCROLL,SWP_DRAWFRAME);
|
|
|
|
pi.GetScrollInfo(pWnd,FALSE);
|
|
|
|
ASSERT(::IsWindow(m_scrlBarVert.GetSafeHwnd()));
|
|
m_scrlBarVert.SetScrollInfo(&pi.scrlInfoVert);
|
|
|
|
pWnd->ShowScrollBar(SB_VERT,FALSE);
|
|
pWnd->ModifyStyle(WS_VSCROLL,NULL,SWP_DRAWFRAME);
|
|
pWnd->ModifyStyle(NULL,WS_VISIBLE);
|
|
}
|
|
else
|
|
{
|
|
pi.scrlInfoVert.cbSize=sizeof(SCROLLINFO);
|
|
pWnd->GetScrollInfo(SB_VERT,&pi.scrlInfoVert);
|
|
}
|
|
|
|
g_bUpdatingScrollInfo=FALSE;
|
|
}
|
|
|
|
|
|
void COXTabViewContainer::UpdateScrollState()
|
|
{
|
|
if(g_bUpdatingScrollState || g_bUpdatingScrollInfo)
|
|
{
|
|
return;
|
|
}
|
|
|
|
g_bUpdatingScrollState=TRUE;
|
|
|
|
CWnd* pWnd=GetActivePage();
|
|
if(pWnd==NULL || !pWnd->IsWindowVisible())
|
|
{
|
|
g_bUpdatingScrollState=FALSE;
|
|
return;
|
|
}
|
|
|
|
PAGEINFO& pi=m_arrPages[GetActivePageIndex()];
|
|
|
|
BOOL bHasScrollHorz=((pWnd->GetStyle() & WS_HSCROLL)==WS_HSCROLL);
|
|
BOOL bHasScrollVert=((pWnd->GetStyle() & WS_VSCROLL)==WS_VSCROLL);
|
|
|
|
if(bHasScrollHorz || bHasScrollVert)
|
|
{
|
|
if(bHasScrollHorz)
|
|
{
|
|
pi.bHasScrollHorz=bHasScrollHorz;
|
|
pWnd->ModifyStyle(WS_HSCROLL,NULL,SWP_DRAWFRAME);
|
|
pWnd->ShowScrollBar(SB_HORZ,FALSE);
|
|
}
|
|
if(bHasScrollVert)
|
|
{
|
|
pi.bHasScrollVert=bHasScrollVert;
|
|
pWnd->ModifyStyle(WS_VSCROLL,NULL,SWP_DRAWFRAME);
|
|
pWnd->ShowScrollBar(SB_VERT,FALSE);
|
|
}
|
|
}
|
|
|
|
pWnd->ModifyStyle(WS_VISIBLE,NULL);
|
|
pWnd->ShowScrollBar(SB_HORZ,TRUE);
|
|
pWnd->ModifyStyle(NULL,WS_HSCROLL,SWP_DRAWFRAME);
|
|
pWnd->ShowScrollBar(SB_VERT,TRUE);
|
|
pWnd->ModifyStyle(NULL,WS_VSCROLL,SWP_DRAWFRAME);
|
|
|
|
pi.GetScrollInfo(pWnd,TRUE);
|
|
if(pi.bHasScrollHorz)
|
|
{
|
|
if(pi.scrlInfoHorz.nMax==0 || pi.scrlInfoHorz.nPage==0 ||
|
|
pi.scrlInfoHorz.nMax<(int)pi.scrlInfoHorz.nPage)
|
|
{
|
|
pi.bHasScrollHorz=FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(pi.scrlInfoHorz.nMax>0 && pi.scrlInfoHorz.nPage>0 &&
|
|
pi.scrlInfoHorz.nMax>=(int)pi.scrlInfoHorz.nPage)
|
|
{
|
|
pi.bHasScrollHorz=TRUE;
|
|
}
|
|
}
|
|
|
|
pi.GetScrollInfo(pWnd,FALSE);
|
|
if(pi.bHasScrollVert)
|
|
{
|
|
if(pi.scrlInfoVert.nMax==0 || pi.scrlInfoVert.nPage==0 ||
|
|
pi.scrlInfoVert.nMax<(int)pi.scrlInfoVert.nPage)
|
|
{
|
|
pi.bHasScrollVert=FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(pi.scrlInfoVert.nMax>0 && pi.scrlInfoVert.nPage>0 &&
|
|
pi.scrlInfoVert.nMax>=(int)pi.scrlInfoVert.nPage)
|
|
{
|
|
pi.bHasScrollVert=TRUE;
|
|
}
|
|
}
|
|
|
|
pWnd->ShowScrollBar(SB_HORZ,FALSE);
|
|
pWnd->ModifyStyle(WS_HSCROLL,NULL,SWP_DRAWFRAME);
|
|
pWnd->ShowScrollBar(SB_VERT,FALSE);
|
|
pWnd->ModifyStyle(WS_VSCROLL,NULL,SWP_DRAWFRAME);
|
|
pWnd->ModifyStyle(NULL,WS_VISIBLE);
|
|
|
|
DWORD dwStyle=GetScrollStyle();
|
|
dwStyle=(pi.bHasScrollHorz ? WS_HSCROLL : 0) |
|
|
(pi.bHasScrollVert ? WS_VSCROLL : 0);
|
|
SetScrollStyle(dwStyle,FALSE);
|
|
|
|
g_bUpdatingScrollState=FALSE;
|
|
}
|
|
|
|
|
|
void COXTabViewContainer::DrawScrollButtons(CDC* pDC)
|
|
{
|
|
ASSERT_VALID(pDC);
|
|
|
|
// scroll to start button
|
|
DrawButton(pDC,m_rectScrollToStartBtn,SCRLSTARTBTN);
|
|
// scroll backward button
|
|
DrawButton(pDC,m_rectScrollBackwardBtn,SCRLBACKWARDBTN);
|
|
// scroll forward button
|
|
DrawButton(pDC,m_rectScrollForwardBtn,SCRLFORWARDBTN);
|
|
// scroll to end button
|
|
DrawButton(pDC,m_rectScrollToEndBtn,SCRLENDBTN);
|
|
}
|
|
|
|
void COXTabViewContainer::DrawTabBtnArea(CDC* pDC)
|
|
{
|
|
ASSERT(m_arrTabBtnRects.GetSize()==GetPageCount());
|
|
|
|
pDC->IntersectClipRect(m_rectTabBtnArea);
|
|
|
|
pDC->FillSolidRect(m_rectTabBtnArea,::GetSysColor(COLOR_BTNFACE));
|
|
|
|
CPen pen(PS_SOLID,1,::GetSysColor(COLOR_WINDOWTEXT));
|
|
CPen* pOldPen=pDC->SelectObject(&pen);
|
|
pDC->MoveTo(m_rectTabBtnArea.left,m_rectTabBtnArea.top);
|
|
pDC->LineTo(m_rectTabBtnArea.right,m_rectTabBtnArea.top);
|
|
|
|
CBrush brush;
|
|
brush.CreateSolidBrush(::GetSysColor(COLOR_BTNFACE));
|
|
CBrush* pOldBrush=pDC->SelectObject(&brush);
|
|
|
|
CFont* pOldFont=NULL;
|
|
ASSERT((HFONT)m_fontTabBtnText!=NULL);
|
|
if((HFONT)m_fontTabBtnText!=NULL)
|
|
pOldFont=pDC->SelectObject(&m_fontTabBtnText);
|
|
|
|
for(int nIndex=0; nIndex<GetPageCount(); nIndex++)
|
|
{
|
|
if(nIndex!=GetActivePageIndex())
|
|
DrawTabButton(pDC,nIndex);
|
|
}
|
|
|
|
|
|
if(GetActivePageIndex()!=-1)
|
|
{
|
|
CBrush brushActive;
|
|
brushActive.CreateSolidBrush(::GetSysColor(COLOR_WINDOW));
|
|
pDC->SelectObject(&brushActive);
|
|
|
|
ASSERT((HFONT)m_fontActiveTabBtnText!=NULL);
|
|
if((HFONT)m_fontActiveTabBtnText!=NULL)
|
|
pDC->SelectObject(&m_fontActiveTabBtnText);
|
|
|
|
DrawTabButton(pDC,GetActivePageIndex());
|
|
}
|
|
|
|
if(pOldFont!=NULL)
|
|
pDC->SelectObject(pOldFont);
|
|
|
|
if(pOldBrush!=NULL)
|
|
pDC->SelectObject(pOldBrush);
|
|
|
|
if(pOldPen!=NULL)
|
|
pDC->SelectObject(pOldPen);
|
|
}
|
|
|
|
void COXTabViewContainer::DrawSplitter(CDC* pDC)
|
|
{
|
|
ASSERT_VALID(pDC);
|
|
|
|
CRect rect=m_rectSplitter;
|
|
|
|
pDC->Draw3dRect(rect,::GetSysColor(COLOR_BTNFACE),
|
|
::GetSysColor(COLOR_WINDOWFRAME));
|
|
rect.DeflateRect(1,1);
|
|
pDC->Draw3dRect(rect,::GetSysColor(COLOR_BTNHILIGHT),
|
|
::GetSysColor(COLOR_BTNSHADOW));
|
|
rect.DeflateRect(1,1);
|
|
|
|
// fill the middle
|
|
COLORREF clr=::GetSysColor(COLOR_BTNFACE);
|
|
#ifdef _MAC
|
|
// just use white for interior if less than 16 colors
|
|
if(pDC->GetDeviceCaps(NUMCOLORS)<16)
|
|
clr=RGB(0xFF,0xFF,0xFF);
|
|
#endif
|
|
pDC->FillSolidRect(rect,clr);
|
|
}
|
|
|
|
void COXTabViewContainer::DrawSizeBar(CDC* pDC)
|
|
{
|
|
ASSERT_VALID(pDC);
|
|
|
|
CWnd* pParentWnd=GetParent();
|
|
ASSERT(pParentWnd!=NULL);
|
|
ASSERT(::IsWindow(pParentWnd->m_hWnd));
|
|
if(pParentWnd->IsKindOf(RUNTIME_CLASS(CMDIChildWnd)) &&
|
|
(pParentWnd->GetStyle()&WS_THICKFRAME)==WS_THICKFRAME &&
|
|
(pParentWnd->GetStyle()&WS_MAXIMIZE)!=WS_MAXIMIZE)
|
|
pDC->DrawFrameControl(m_rectSizeBar,DFC_SCROLL,DFCS_SCROLLSIZEGRIP);
|
|
else
|
|
pDC->FillSolidRect(m_rectSizeBar,::GetSysColor(COLOR_BTNFACE));
|
|
}
|
|
|
|
void COXTabViewContainer::DrawButton(CDC* pDC, CRect rect,
|
|
HITTEST nButtonType) const
|
|
{
|
|
ASSERT_VALID(pDC);
|
|
|
|
pDC->FillSolidRect(rect,::GetSysColor(COLOR_BTNFACE));
|
|
|
|
COLORREF clrTopLeft;
|
|
COLORREF clrBottomRight;
|
|
if(m_nPressedScrlBtn==nButtonType)
|
|
{
|
|
CPoint point;
|
|
::GetCursorPos(&point);
|
|
ScreenToClient(&point);
|
|
if(rect.PtInRect(point))
|
|
{
|
|
clrBottomRight=::GetSysColor(COLOR_BTNFACE);
|
|
clrTopLeft=::GetSysColor(COLOR_BTNFACE);
|
|
rect.OffsetRect(1,1);
|
|
}
|
|
else
|
|
{
|
|
clrTopLeft=::GetSysColor(COLOR_BTNHILIGHT);
|
|
clrBottomRight=::GetSysColor(COLOR_BTNSHADOW);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
clrTopLeft=::GetSysColor(COLOR_BTNHILIGHT);
|
|
clrBottomRight=::GetSysColor(COLOR_BTNSHADOW);
|
|
}
|
|
|
|
pDC->Draw3dRect(rect,clrTopLeft,clrBottomRight);
|
|
|
|
|
|
// draw arrows
|
|
//
|
|
rect.DeflateRect(2,2);
|
|
CRect rectCopy=rect;
|
|
|
|
POINT arrPoints[3];
|
|
CRgn rgn;
|
|
CBrush brush;
|
|
brush.CreateSolidBrush(::GetSysColor(COLOR_WINDOWTEXT));
|
|
|
|
switch(nButtonType)
|
|
{
|
|
// start
|
|
case SCRLSTARTBTN:
|
|
rectCopy.DeflateRect(rectCopy.Width()/4,rectCopy.Height()/6);
|
|
rectCopy.left+=rectCopy.Width()/4-2;
|
|
if(rectCopy.Height()%2==0)
|
|
rectCopy.bottom+=1;
|
|
rectCopy.right=rectCopy.left+2;
|
|
pDC->FillSolidRect(rectCopy,::GetSysColor(COLOR_WINDOWTEXT));
|
|
// backward
|
|
case SCRLBACKWARDBTN:
|
|
rectCopy=rect;
|
|
rectCopy.DeflateRect(rectCopy.Width()/4,rectCopy.Height()/6);
|
|
if(nButtonType==SCRLSTARTBTN)
|
|
rectCopy.left+=rectCopy.Width()/4;
|
|
else
|
|
rectCopy.right-=rectCopy.Width()/4;
|
|
if(rectCopy.Height()%2==0)
|
|
rectCopy.bottom++;
|
|
arrPoints[0].x=rectCopy.right;
|
|
arrPoints[0].y=rectCopy.top-1;
|
|
arrPoints[1].x=rectCopy.right;
|
|
arrPoints[1].y=rectCopy.bottom;
|
|
arrPoints[2].x=rectCopy.left;
|
|
arrPoints[2].y=rectCopy.top+rectCopy.Height()/2;
|
|
rgn.CreatePolygonRgn(arrPoints,3,WINDING);
|
|
pDC->FillRgn(&rgn,&brush);
|
|
break;
|
|
// end
|
|
case SCRLENDBTN:
|
|
rectCopy.DeflateRect(rectCopy.Width()/4,rectCopy.Height()/6);
|
|
rectCopy.right-=rectCopy.Width()/4-2;
|
|
if(rectCopy.Height()%2==0)
|
|
rectCopy.bottom+=1;
|
|
rectCopy.left=rectCopy.right-2;
|
|
pDC->FillSolidRect(rectCopy,::GetSysColor(COLOR_WINDOWTEXT));
|
|
// forward
|
|
case SCRLFORWARDBTN:
|
|
rectCopy=rect;
|
|
rectCopy.DeflateRect(rectCopy.Width()/4,rectCopy.Height()/6);
|
|
if(nButtonType==SCRLENDBTN)
|
|
rectCopy.right-=rectCopy.Width()/4;
|
|
else
|
|
rectCopy.left+=rectCopy.Width()/4;
|
|
if(rectCopy.Height()%2==0)
|
|
rectCopy.bottom++;
|
|
arrPoints[0].x=rectCopy.right;
|
|
arrPoints[0].y=rectCopy.top+rectCopy.Height()/2;
|
|
arrPoints[1].x=rectCopy.left;
|
|
arrPoints[1].y=rectCopy.top-1;
|
|
arrPoints[2].x=rectCopy.left;
|
|
arrPoints[2].y=rectCopy.bottom;
|
|
rgn.CreatePolygonRgn(arrPoints,3,WINDING);
|
|
pDC->FillRgn(&rgn,&brush);
|
|
break;
|
|
default:
|
|
ASSERT(FALSE);
|
|
}
|
|
}
|
|
|
|
void COXTabViewContainer::DrawTabButton(CDC* pDC, int nIndex) const
|
|
{
|
|
ASSERT(nIndex>=0 && nIndex<GetPageCount());
|
|
|
|
CRect rect=m_arrTabBtnRects[nIndex];
|
|
rect+=m_rectTabBtnArea.TopLeft();
|
|
rect.OffsetRect(m_nTabBtnAreaOrigin,0);
|
|
if(rect.right>m_rectTabBtnArea.left && rect.left<m_rectTabBtnArea.right)
|
|
{
|
|
rect.bottom=m_rectTabBtnArea.bottom;
|
|
|
|
POINT arrPoints[4];
|
|
arrPoints[0].x=rect.left;
|
|
arrPoints[0].y=rect.top;
|
|
arrPoints[1].x=rect.left+ID_TABBTNOVERLAPSIZE;
|
|
arrPoints[1].y=rect.bottom;
|
|
arrPoints[2].x=rect.right-ID_TABBTNOVERLAPSIZE;
|
|
arrPoints[2].y=rect.bottom;
|
|
arrPoints[3].x=rect.right;
|
|
arrPoints[3].y=rect.top;
|
|
|
|
CPen penTop(PS_SOLID,1,::GetSysColor(COLOR_BTNHILIGHT));
|
|
CPen penBottom(PS_SOLID,1,::GetSysColor(COLOR_BTNSHADOW));
|
|
CPen* pOldPen=NULL;
|
|
if(nIndex==GetActivePageIndex())
|
|
{
|
|
pDC->Polygon(arrPoints,4);
|
|
|
|
pOldPen=pDC->SelectObject(&penTop);
|
|
arrPoints[0].x++;
|
|
pDC->MoveTo(arrPoints[0]);
|
|
pDC->LineTo(arrPoints[3]);
|
|
|
|
pDC->SelectObject(&penBottom);
|
|
arrPoints[1].y--;
|
|
arrPoints[2].y--;
|
|
pDC->MoveTo(arrPoints[1]);
|
|
pDC->LineTo(arrPoints[2]);
|
|
}
|
|
else
|
|
{
|
|
pDC->Polygon(arrPoints,4);
|
|
|
|
pOldPen=pDC->SelectObject(&penBottom);
|
|
arrPoints[1].y--;
|
|
arrPoints[2].y--;
|
|
pDC->MoveTo(arrPoints[1]);
|
|
pDC->LineTo(arrPoints[2]);
|
|
arrPoints[2].x--;
|
|
arrPoints[3].x--;
|
|
pDC->MoveTo(arrPoints[2]);
|
|
pDC->LineTo(arrPoints[3]);
|
|
|
|
pDC->SelectObject(&penTop);
|
|
arrPoints[0].x+=2;
|
|
arrPoints[0].y++;
|
|
arrPoints[1].x++;
|
|
pDC->MoveTo(arrPoints[0]);
|
|
pDC->LineTo(arrPoints[1]);
|
|
}
|
|
if(pOldPen!=NULL)
|
|
pDC->SelectObject(pOldPen);
|
|
|
|
CString sTitle=GetPageTitle(nIndex);
|
|
if(!sTitle.IsEmpty())
|
|
{
|
|
COLORREF oldColor=pDC->SetTextColor(::GetSysColor(COLOR_WINDOWTEXT));
|
|
int nOldBkMode=pDC->SetBkMode(TRANSPARENT);
|
|
pDC->DrawText(sTitle,rect,DT_CENTER|DT_SINGLELINE|DT_VCENTER);
|
|
pDC->SetBkMode(nOldBkMode);
|
|
pDC->SetTextColor(oldColor);
|
|
}
|
|
}
|
|
}
|
|
|
|
int COXTabViewContainer::HitTest(const CPoint& point) const
|
|
{
|
|
if(m_rectSplitter.PtInRect(point))
|
|
return SPLITTER;
|
|
else if(m_rectScrollBarHorz.PtInRect(point))
|
|
return SCROLLBARHORZ;
|
|
else if(m_rectScrollBarVert.PtInRect(point))
|
|
return SCROLLBARVERT;
|
|
else if(m_rectScrollToStartBtn.PtInRect(point))
|
|
return SCRLSTARTBTN;
|
|
else if(m_rectScrollBackwardBtn.PtInRect(point))
|
|
return SCRLBACKWARDBTN;
|
|
else if(m_rectScrollForwardBtn.PtInRect(point))
|
|
return SCRLFORWARDBTN;
|
|
else if(m_rectScrollToEndBtn.PtInRect(point))
|
|
return SCRLENDBTN;
|
|
else if(m_rectTabBtnArea.PtInRect(point))
|
|
{
|
|
// test here for tab buttons
|
|
for(int nIndex=0; nIndex<GetPageCount(); nIndex++)
|
|
{
|
|
CRect rect=m_arrTabBtnRects[nIndex];
|
|
rect+=m_rectTabBtnArea.TopLeft();
|
|
rect.OffsetRect(m_nTabBtnAreaOrigin,0);
|
|
rect.bottom=m_rectTabBtnArea.bottom;
|
|
if(rect.PtInRect(point))
|
|
return nIndex;
|
|
}
|
|
|
|
return TABBTNAREA;
|
|
}
|
|
else if(m_rectSizeBar.PtInRect(point))
|
|
return SIZEBAR;
|
|
else if(m_rectPage.PtInRect(point))
|
|
return PAGE;
|
|
|
|
return NONE;
|
|
}
|
|
|
|
void COXTabViewContainer::RedrawScrollButton(HITTEST hitTest)
|
|
{
|
|
switch(hitTest)
|
|
{
|
|
case SCRLSTARTBTN:
|
|
RedrawWindow(m_rectScrollToStartBtn);
|
|
break;
|
|
case SCRLBACKWARDBTN:
|
|
RedrawWindow(m_rectScrollBackwardBtn);
|
|
break;
|
|
case SCRLFORWARDBTN:
|
|
RedrawWindow(m_rectScrollForwardBtn);
|
|
break;
|
|
case SCRLENDBTN:
|
|
RedrawWindow(m_rectScrollToEndBtn);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void COXTabViewContainer::ScrollPage(HITTEST nScrlBtn)
|
|
{
|
|
BOOL m_bHasScrolled=FALSE;
|
|
|
|
switch(nScrlBtn)
|
|
{
|
|
case SCRLSTARTBTN:
|
|
if(CanScrollToStart())
|
|
{
|
|
m_nTabBtnAreaOrigin=0;
|
|
m_bHasScrolled=TRUE;
|
|
}
|
|
break;
|
|
case SCRLBACKWARDBTN:
|
|
if(CanScrollBackward())
|
|
{
|
|
m_nTabBtnAreaOrigin+=ID_SCROLLTABBTNAREASTEP;
|
|
m_nTabBtnAreaOrigin=
|
|
m_nTabBtnAreaOrigin>0 ? 0 : m_nTabBtnAreaOrigin;
|
|
m_bHasScrolled=TRUE;
|
|
}
|
|
break;
|
|
case SCRLFORWARDBTN:
|
|
if(CanScrollForward())
|
|
{
|
|
m_nTabBtnAreaOrigin-=ID_SCROLLTABBTNAREASTEP;
|
|
CRect rect=m_arrTabBtnRects[GetPageCount()-1];
|
|
rect+=m_rectTabBtnArea.TopLeft();
|
|
if(rect.right+m_nTabBtnAreaOrigin<m_rectTabBtnArea.right)
|
|
m_nTabBtnAreaOrigin=m_rectTabBtnArea.right-rect.right;
|
|
m_bHasScrolled=TRUE;
|
|
}
|
|
break;
|
|
case SCRLENDBTN:
|
|
if(CanScrollToEnd())
|
|
{
|
|
CRect rect=m_arrTabBtnRects[GetPageCount()-1];
|
|
rect+=m_rectTabBtnArea.TopLeft();
|
|
m_nTabBtnAreaOrigin=m_rectTabBtnArea.right-rect.right;
|
|
m_bHasScrolled=TRUE;
|
|
}
|
|
break;
|
|
default:
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
if(m_bHasScrolled)
|
|
RedrawTabBtnArea();
|
|
}
|
|
|
|
|
|
void COXTabViewContainer::StartTracking(const CPoint& point)
|
|
{
|
|
ASSERT(m_nPressedScrlBtn==NONE);
|
|
m_nPressedScrlBtn=NONE;
|
|
|
|
int hitTest=HitTest(point);
|
|
if(hitTest==SCRLSTARTBTN || hitTest==SCRLBACKWARDBTN ||
|
|
hitTest==SCRLFORWARDBTN || hitTest==SCRLENDBTN)
|
|
{
|
|
SetCapture();
|
|
m_nPressedScrlBtn=(HITTEST)hitTest;
|
|
m_bIsScrlBtnPressed=TRUE;
|
|
RedrawScrollButton(m_nPressedScrlBtn);
|
|
ScrollPage(m_nPressedScrlBtn);
|
|
m_nScrollPageTimer=SetTimer(IDT_SCROLLPAGE_TIMER,
|
|
ID_SCROLLPAGE_DELAY,NULL);
|
|
}
|
|
else if(hitTest==SPLITTER)
|
|
{
|
|
SetCapture();
|
|
m_bIsSplitterPressed=TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
void COXTabViewContainer::StopTracking(const CPoint& point)
|
|
{
|
|
if(::GetCapture()==GetSafeHwnd())
|
|
{
|
|
::ReleaseCapture();
|
|
}
|
|
|
|
if(m_nPressedScrlBtn!=NONE)
|
|
{
|
|
int hitTest=HitTest(point);
|
|
if((int)m_nPressedScrlBtn==hitTest && m_nScrollPageTimer!=-1)
|
|
{
|
|
KillTimer(m_nScrollPageTimer);
|
|
m_nScrollPageTimer=-1;
|
|
}
|
|
|
|
HITTEST nOldPressedScrlBtn=m_nPressedScrlBtn;
|
|
m_nPressedScrlBtn=NONE;
|
|
m_bIsScrlBtnPressed=FALSE;
|
|
RedrawScrollButton(nOldPressedScrlBtn);
|
|
}
|
|
else if(m_bIsSplitterPressed)
|
|
{
|
|
m_bIsSplitterPressed=FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
DWORD COXTabViewContainer::GetUniqueId()
|
|
{
|
|
int nCount=PtrToInt(m_arrUniqueIDs.GetSize());
|
|
ASSERT(nCount>0);
|
|
DWORD dwUniqueID=m_arrUniqueIDs[nCount-1];
|
|
if(nCount==1)
|
|
{
|
|
m_arrUniqueIDs.SetAt(nCount-1,dwUniqueID+1);
|
|
}
|
|
return dwUniqueID;
|
|
}
|
|
|
|
|
|
void COXTabViewContainer::EnsureTabBtnVisible(int nIndex,
|
|
BOOL bPartialOk/*=FALSE*/)
|
|
{
|
|
ASSERT(nIndex>=0 && nIndex<GetPageCount());
|
|
|
|
if(m_rectTabBtnArea.Width()>0 && nIndex>=0 && nIndex<GetPageCount())
|
|
{
|
|
CRect rect=m_arrTabBtnRects[nIndex];
|
|
rect+=m_rectTabBtnArea.TopLeft();
|
|
rect.OffsetRect(m_nTabBtnAreaOrigin,0);
|
|
if(rect.left>m_rectTabBtnArea.right ||
|
|
rect.right<m_rectTabBtnArea.left ||
|
|
(rect.left<m_rectTabBtnArea.left &&
|
|
rect.right<m_rectTabBtnArea.right && !bPartialOk) ||
|
|
(rect.left>m_rectTabBtnArea.left &&
|
|
rect.right>m_rectTabBtnArea.right && !bPartialOk))
|
|
{
|
|
if(rect.left<m_rectTabBtnArea.left)
|
|
{
|
|
m_nTabBtnAreaOrigin+=m_rectTabBtnArea.left-rect.left;
|
|
if(nIndex>0)
|
|
m_nTabBtnAreaOrigin+=m_rectTabBtnArea.Width()/2<20 ?
|
|
m_rectTabBtnArea.Width()/2 : 20;
|
|
}
|
|
else
|
|
{
|
|
m_nTabBtnAreaOrigin+=m_rectTabBtnArea.right-rect.right;
|
|
if(nIndex<GetPageCount()-1)
|
|
m_nTabBtnAreaOrigin-=m_rectTabBtnArea.Width()/2<20 ?
|
|
m_rectTabBtnArea.Width()/2 : 20;
|
|
}
|
|
RedrawTabBtnArea();
|
|
}
|
|
}
|
|
}
|