// ========================================================================== // 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.x0 ? 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 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=0 && nIndex1 ? 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=0 && nIndexm_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_nActivePageIndexm_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.rightGetStyle()&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; nIndexSelectObject(&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 && nIndexm_rectTabBtnArea.left && rect.leftPolygon(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; nIndex0 ? 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_nTabBtnAreaOrigin0); 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 && nIndex0 && nIndex>=0 && nIndexm_rectTabBtnArea.right || rect.rightm_rectTabBtnArea.left && rect.right>m_rectTabBtnArea.right && !bPartialOk)) { if(rect.left0) m_nTabBtnAreaOrigin+=m_rectTabBtnArea.Width()/2<20 ? m_rectTabBtnArea.Width()/2 : 20; } else { m_nTabBtnAreaOrigin+=m_rectTabBtnArea.right-rect.right; if(nIndex