487 lines
25 KiB
C++
487 lines
25 KiB
C++
// ==========================================================================
|
||
// Class Implementation : COXDockPropertySheet
|
||
// ==========================================================================
|
||
|
||
// Source file : OXDckPSh.cpp
|
||
|
||
// 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" // standard MFC include
|
||
#include "OXDckPSh.h" // class specification
|
||
#include "OXDckPPg.h"
|
||
#include "..\include\oxdckpsh.h"
|
||
#include "OXSzMiniDockFrmWnd.h"
|
||
|
||
#include "UTB64Bit.h"
|
||
|
||
#ifdef _DEBUG
|
||
#undef THIS_FILE
|
||
static char BASED_CODE THIS_FILE[] = __FILE__;
|
||
#endif
|
||
|
||
#define TABBORDER_OPENSPACE 6
|
||
#define TAB_ID 1000
|
||
|
||
/////////////////////////////////////////////////////////////////////////////
|
||
// Definition of static members
|
||
|
||
|
||
// Data members -------------------------------------------------------------
|
||
// protected:
|
||
|
||
// CString m_sCaption;
|
||
// --- Title of this sheet
|
||
|
||
// CTabCtrl m_tabCtrl;
|
||
// --- The tabcontrol that will recieve all the pages of this sheet
|
||
|
||
// CObArray m_pageArray;
|
||
// --- An array where all added pages will be stored
|
||
|
||
// CObList m_DynPageList
|
||
// --- A list to keep track of all dynamic added pages.
|
||
|
||
// CRect m_rectTabArea;
|
||
// --- The rectangle wherein all pages will be shown
|
||
|
||
// int m_nCurrentSelection;
|
||
// --- The index of the currently selected page
|
||
|
||
// private:
|
||
|
||
// Member functions ---------------------------------------------------------
|
||
// public:
|
||
|
||
COXDockPropertySheet::COXDockPropertySheet(LPCTSTR pszCaption /*= NULL*/)
|
||
: COXDialogBar(),
|
||
m_rectTabArea(0,0,0,0),
|
||
m_nCurrentSelection(-1)
|
||
{
|
||
if (pszCaption)
|
||
m_sCaption = pszCaption;
|
||
Construct();
|
||
}
|
||
|
||
COXDockPropertySheet::COXDockPropertySheet(UINT nIDCaption)
|
||
: COXDialogBar(),
|
||
m_rectTabArea(0,0,0,0),
|
||
m_nCurrentSelection(-1)
|
||
{
|
||
m_sCaption.LoadString(nIDCaption);
|
||
Construct();
|
||
}
|
||
|
||
void COXDockPropertySheet::Construct()
|
||
{
|
||
//{{AFX_DATA_INIT(COXDockPropertySheet)
|
||
// NOTE: the ClassWizard will add member initialization here
|
||
//}}AFX_DATA_INIT
|
||
}
|
||
|
||
|
||
COXDockPropertySheet::~COXDockPropertySheet()
|
||
{
|
||
for (int nPage = 0 ; nPage < m_pageArray.GetSize() ; nPage++)
|
||
{
|
||
COXDockPropertyPage* pPage = (COXDockPropertyPage*) m_pageArray[nPage];
|
||
|
||
if (m_DynPageList.Find(pPage) != NULL)
|
||
{
|
||
ASSERT(pPage->IsKindOf(RUNTIME_CLASS(COXDockPropertyPage)));
|
||
if (pPage->IsDynamicPage())
|
||
{
|
||
pPage->DestroyWindow();
|
||
delete pPage;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void COXDockPropertySheet::AdjustAllPages()
|
||
{
|
||
// position all child pages, in the tabcontrol
|
||
for (int nPage = 0 ; nPage < m_pageArray.GetSize() ; nPage++)
|
||
{
|
||
// position the dialog/property-page within the tab control
|
||
((CWnd*)(m_pageArray[nPage]))->SetWindowPos(NULL, m_rectTabArea.left, m_rectTabArea.top, 0, 0,
|
||
SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE);
|
||
|
||
}
|
||
|
||
if (m_pageArray.GetSize() > 0)
|
||
SelectPage(m_nCurrentSelection != -1 ? m_nCurrentSelection : 0);
|
||
}
|
||
|
||
|
||
BOOL COXDockPropertySheet::SelectPage(int nNextSel)
|
||
{
|
||
if (GetPageCount() == 0)
|
||
{
|
||
m_nCurrentSelection = -1;
|
||
return FALSE;
|
||
}
|
||
|
||
if (nNextSel < -1 || nNextSel >= GetPageCount())
|
||
return FALSE;
|
||
|
||
if (nNextSel != -1)
|
||
{
|
||
COXDockPropertyPage* pNextPage = (COXDockPropertyPage*)m_pageArray[nNextSel];
|
||
|
||
if (m_nCurrentSelection != nNextSel)
|
||
{
|
||
if (m_nCurrentSelection > -1) // Thanks Franco
|
||
if (!((COXDockPropertyPage*)m_pageArray[m_nCurrentSelection])->OnKillActive())
|
||
return FALSE;
|
||
|
||
pNextPage->EnableWindow(TRUE);
|
||
if (!pNextPage->OnSetActive())
|
||
{
|
||
pNextPage->EnableWindow(FALSE);
|
||
return FALSE;
|
||
}
|
||
|
||
for (int nPage = 0 ; nPage < m_pageArray.GetSize() ; nPage++)
|
||
{
|
||
if (nPage != nNextSel)
|
||
{
|
||
((COXDockPropertyPage*)m_pageArray[nPage])->ShowWindow(SW_HIDE);
|
||
((COXDockPropertyPage*)m_pageArray[nPage])->EnableWindow(FALSE);
|
||
}
|
||
}
|
||
|
||
pNextPage->ShowWindow(SW_SHOW);
|
||
m_nCurrentSelection = nNextSel;
|
||
m_tabCtrl.SetCurSel(m_nCurrentSelection);
|
||
}
|
||
|
||
pNextPage->SetFocus();
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
BOOL COXDockPropertySheet::Create(CWnd* pParentWnd, UINT nDlgStyle,
|
||
UINT nTabStyle /* = WS_CHILD | WS_VISIBLE | TCS_TABS | TCS_SINGLELINE | TCS_RAGGEDRIGHT */,
|
||
UINT nID /* = 1 */)
|
||
{
|
||
BOOL bSuccess = COXDialogBar::Create(pParentWnd, nDlgStyle, nID);
|
||
|
||
if (bSuccess)
|
||
{
|
||
CRect ClientRect(0,0,0,0);
|
||
bSuccess = m_tabCtrl.Create(nTabStyle, ClientRect, this, TAB_ID);
|
||
|
||
for (int nPage=0 ; nPage < m_pageArray.GetSize() ; nPage++)
|
||
AddPage((COXDockPropertyPage*) m_pageArray[nPage]);
|
||
|
||
AdjustAllPages();
|
||
}
|
||
|
||
return bSuccess;
|
||
}
|
||
|
||
COXDockPropertyPage* COXDockPropertySheet::GetActivePage() const
|
||
{
|
||
ASSERT_VALID(this);
|
||
if (m_nCurrentSelection == -1)
|
||
return NULL;
|
||
|
||
return GetPage(GetActiveIndex());
|
||
}
|
||
|
||
int COXDockPropertySheet::GetPageCount() const
|
||
{
|
||
ASSERT_VALID(this);
|
||
|
||
if (m_hWnd == NULL || m_tabCtrl.m_hWnd == NULL)
|
||
return PtrToInt(m_pageArray.GetSize());
|
||
|
||
return m_tabCtrl.GetItemCount();
|
||
}
|
||
|
||
int COXDockPropertySheet::GetActiveIndex() const
|
||
{
|
||
if (m_hWnd == NULL || m_tabCtrl.m_hWnd == NULL)
|
||
return m_nCurrentSelection;
|
||
|
||
return m_tabCtrl.GetCurSel();
|
||
}
|
||
|
||
BOOL COXDockPropertySheet::SetActivePage(int nPage)
|
||
{
|
||
if (m_hWnd == NULL || m_tabCtrl.m_hWnd == NULL)
|
||
{
|
||
m_nCurrentSelection = nPage;
|
||
return TRUE;
|
||
}
|
||
|
||
return SelectPage(nPage);
|
||
}
|
||
|
||
int COXDockPropertySheet::GetPageIndex(COXDockPropertyPage* pPage)
|
||
{
|
||
for (int i = 0; i < GetPageCount(); i++)
|
||
{
|
||
if (GetPage(i) == pPage)
|
||
return i;
|
||
}
|
||
return -1; // pPage not found
|
||
}
|
||
|
||
void COXDockPropertySheet::SetTitle(LPCTSTR lpszText)
|
||
{
|
||
if (m_hWnd != NULL)
|
||
SetWindowText(lpszText);
|
||
|
||
m_sCaption = lpszText;
|
||
}
|
||
|
||
BOOL COXDockPropertySheet::AddPage(COXDockPropertyPage* pPage,
|
||
BOOL bAdjust /* = FALSE */)
|
||
{
|
||
// when tab control not yet created, just add pages to an array
|
||
// pages will be created later.
|
||
if (m_tabCtrl.m_hWnd != NULL)
|
||
{
|
||
CRect PageRect;
|
||
TC_ITEM tie;
|
||
|
||
pPage->Create(pPage->m_nID, &m_tabCtrl);
|
||
if (pPage->m_sCaption.IsEmpty())
|
||
pPage->GetWindowText(pPage->m_sCaption);
|
||
pPage->ModifyStyle(WS_BORDER | WS_CAPTION, 0);
|
||
|
||
// Add a tab for each of the child dialog boxes.
|
||
tie.mask = TCIF_TEXT | TCIF_IMAGE;
|
||
tie.iImage = -1;
|
||
tie.pszText = pPage->m_sCaption.GetBufferSetLength(pPage->m_sCaption.GetLength());
|
||
pPage->m_sCaption.ReleaseBuffer();
|
||
|
||
// already add the tab to the tabctrl otherwise, the Function AdjustRect
|
||
// returns a adjusted rect without leaving space for the TABS. This is specifically
|
||
// seen when adding the first page.
|
||
int count = GetPageCount();
|
||
m_tabCtrl.InsertItem(count, &tie);
|
||
|
||
// Calculate the biggest dialog and size the tabcontrol, control bar
|
||
// accordingly
|
||
pPage->GetWindowRect(&PageRect);
|
||
PageRect.OffsetRect(-PageRect.left, -PageRect.top);
|
||
PageRect.OffsetRect(m_rectTabArea.left, m_rectTabArea.top);
|
||
PageRect.right = __max(PageRect.right, m_rectTabArea.right);
|
||
PageRect.bottom = __max(PageRect.bottom, m_rectTabArea.bottom);
|
||
if (PageRect != m_rectTabArea)
|
||
{
|
||
// size the tab control
|
||
CRect TabCtrlArea(PageRect);
|
||
m_tabCtrl.AdjustRect(TRUE, TabCtrlArea);
|
||
m_tabCtrl.SetWindowPos(NULL, TABBORDER_OPENSPACE, TABBORDER_OPENSPACE,
|
||
TabCtrlArea.Width(), TabCtrlArea.Height(),
|
||
SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);
|
||
m_tabCtrl.GetWindowRect(&TabCtrlArea);
|
||
TabCtrlArea.OffsetRect(-TabCtrlArea.left, -TabCtrlArea.top);
|
||
m_tabCtrl.AdjustRect(FALSE, TabCtrlArea);
|
||
m_rectTabArea = TabCtrlArea;
|
||
|
||
// Size the control bar
|
||
m_tabCtrl.GetWindowRect(&TabCtrlArea);
|
||
TabCtrlArea.InflateRect(TABBORDER_OPENSPACE, TABBORDER_OPENSPACE);
|
||
m_sizeDefault.cx = TabCtrlArea.Width();
|
||
m_sizeDefault.cy = TabCtrlArea.Height();
|
||
|
||
}
|
||
|
||
int size = PtrToInt(m_pageArray.GetSize());
|
||
if (count + 1 > size)
|
||
{
|
||
m_pageArray.Add(pPage);
|
||
if (pPage->IsDynamicPage())
|
||
m_DynPageList.AddTail(pPage);
|
||
}
|
||
|
||
pPage->SendMessage(WM_NCACTIVATE, TRUE);
|
||
|
||
if (bAdjust)
|
||
AdjustAllPages();
|
||
}
|
||
else
|
||
{
|
||
m_pageArray.Add(pPage);
|
||
if (pPage->IsDynamicPage())
|
||
m_DynPageList.AddTail(pPage);
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
void COXDockPropertySheet::RemovePage(int nPage)
|
||
{
|
||
ASSERT_VALID(this);
|
||
|
||
if (0 <= nPage && nPage < GetPageCount())
|
||
{
|
||
::LockWindowUpdate(m_tabCtrl.m_hWnd);
|
||
// remove the page externally
|
||
if (m_hWnd != NULL && m_tabCtrl.m_hWnd != NULL)
|
||
{
|
||
COXDockPropertyPage* pPage = (COXDockPropertyPage*) m_pageArray[nPage];
|
||
ASSERT(pPage->GetRuntimeClass()->IsDerivedFrom(RUNTIME_CLASS(COXDockPropertyPage)));
|
||
|
||
m_tabCtrl.DeleteItem(nPage);
|
||
pPage->ShowWindow(SW_HIDE);
|
||
pPage->EnableWindow(FALSE);
|
||
POSITION PagePos;
|
||
if ((PagePos = m_DynPageList.Find(pPage)) != NULL && pPage->IsDynamicPage())
|
||
{
|
||
m_DynPageList.RemoveAt(PagePos);
|
||
pPage->DestroyWindow();
|
||
delete pPage;
|
||
}
|
||
}
|
||
|
||
// remove the page from internal list
|
||
m_pageArray.RemoveAt(nPage);
|
||
|
||
int nNewCurSel(-1);
|
||
if (nPage < m_nCurrentSelection)
|
||
{
|
||
// should there be no more items, then SelectPage will reset the current selction
|
||
nNewCurSel = m_nCurrentSelection - 1;
|
||
}
|
||
else if (nPage == m_nCurrentSelection)
|
||
{
|
||
if (nPage == 0)
|
||
nNewCurSel = 0;
|
||
else
|
||
nNewCurSel = m_nCurrentSelection - 1;
|
||
|
||
// To force SelectPage to select a new page
|
||
m_nCurrentSelection = -1;
|
||
}
|
||
|
||
SelectPage(nNewCurSel);
|
||
::LockWindowUpdate(NULL);
|
||
}
|
||
}
|
||
|
||
int COXDockPropertySheet::NextPageIndex(int nPage)
|
||
{
|
||
return (nPage + 1) % GetPageCount();
|
||
}
|
||
|
||
int COXDockPropertySheet::PrevPageIndex(int nPage)
|
||
{
|
||
return ((nPage - 1) % GetPageCount()) >= 0 ? (nPage - 1) % GetPageCount(): ((nPage - 1) % GetPageCount()) + GetPageCount();
|
||
}
|
||
|
||
void COXDockPropertySheet::DoDataExchange(CDataExchange* pDX)
|
||
{
|
||
COXDialogBar::DoDataExchange(pDX);
|
||
//{{AFX_DATA_MAP(COXDockPropertySheet)
|
||
//}}AFX_DATA_MAP
|
||
}
|
||
|
||
|
||
BEGIN_MESSAGE_MAP(COXDockPropertySheet, COXDialogBar)
|
||
//{{AFX_MSG_MAP(COXDockPropertySheet)
|
||
ON_NOTIFY(TCN_SELCHANGING, TAB_ID, OnSelchangingTab)
|
||
ON_NOTIFY(TCN_SELCHANGE, TAB_ID, OnSelchangeTab)
|
||
//}}AFX_MSG_MAP
|
||
ON_WM_MOVE()
|
||
END_MESSAGE_MAP()
|
||
|
||
/////////////////////////////////////////////////////////////////////////////
|
||
// COXDockPropertySheet message handlers
|
||
|
||
void COXDockPropertySheet::OnSelchangingTab(NMHDR* /* pNMHDR */, LRESULT* pResult)
|
||
{
|
||
COXDockPropertyPage* pPage = GetActivePage();
|
||
if (pPage != NULL)
|
||
*pResult = !pPage->OnKillActive();
|
||
}
|
||
|
||
void COXDockPropertySheet::OnSelchangeTab(NMHDR* /* pNMHDR */, LRESULT* pResult)
|
||
{
|
||
int nSel = m_tabCtrl.GetCurSel();
|
||
if (nSel != -1)
|
||
*pResult = SelectPage(nSel);
|
||
}
|
||
|
||
#if _MSC_VER < 1400
|
||
int COXDockPropertySheet::OnToolHitTest(CPoint point, TOOLINFO* pTI) const
|
||
#else
|
||
INT_PTR COXDockPropertySheet::OnToolHitTest(CPoint point, TOOLINFO* pTI) const
|
||
#endif
|
||
{
|
||
TC_HITTESTINFO HitInfo;
|
||
|
||
CRect TabRect;
|
||
m_tabCtrl.GetWindowRect(TabRect);
|
||
ClientToScreen(&point);
|
||
if (TabRect.PtInRect(point))
|
||
{
|
||
m_tabCtrl.ScreenToClient(&point);
|
||
|
||
HitInfo.pt = point;
|
||
m_tabCtrl.HitTest(&HitInfo);
|
||
|
||
if (HitInfo.flags == TCHT_NOWHERE)
|
||
return -1;
|
||
}
|
||
|
||
return CWnd::OnToolHitTest(point, pTI);
|
||
}
|
||
|
||
BOOL COXDockPropertySheet::PreTranslateMessage(MSG* pMsg)
|
||
{
|
||
ASSERT_VALID(this);
|
||
|
||
// allow tooltip messages to be filtered
|
||
if (CWnd::PreTranslateMessage(pMsg))
|
||
return TRUE;
|
||
|
||
// allow sheet to translate Ctrl+Tab, Shift+Ctrl+Tab,
|
||
// Ctrl+PageUp, and Ctrl+PageDown
|
||
if (pMsg->message == WM_KEYDOWN && GetAsyncKeyState(VK_CONTROL) < 0)
|
||
{
|
||
switch (pMsg->wParam)
|
||
{
|
||
case VK_TAB:
|
||
case VK_PRIOR:
|
||
case VK_NEXT:
|
||
|
||
if (GetAsyncKeyState(VK_SHIFT) < 0 || pMsg->wParam == VK_PRIOR)
|
||
SetActivePage(PrevPageIndex(GetActiveIndex()));
|
||
else
|
||
SetActivePage(NextPageIndex(GetActiveIndex()));
|
||
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
// handle rest with IsDialogMessage
|
||
return PreTranslateInput(pMsg);
|
||
}
|
||
|
||
void COXDockPropertySheet::OnMove(int x, int y)
|
||
{
|
||
COXDialogBar::OnMove(x, y);
|
||
|
||
COXSizableMiniDockFrameWnd* pMiniFrame = DYNAMIC_DOWNCAST(COXSizableMiniDockFrameWnd, GetParent()->GetParent());
|
||
if (pMiniFrame != NULL)
|
||
pMiniFrame->GetContainedBarType();
|
||
}
|