2025-11-27 16:46:48 +09:00

488 lines
12 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();
}