You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1372 lines
32 KiB
C++
1372 lines
32 KiB
C++
// SplitterWndXT.cpp : implementation file
|
|
//
|
|
// This file is a part of the XTREME CONTROLS MFC class library.
|
|
// (c)1998-2012 Codejock Software, All Rights Reserved.
|
|
//
|
|
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
|
|
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
|
|
// CONSENT OF CODEJOCK SOFTWARE.
|
|
//
|
|
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
|
|
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
|
|
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
|
|
// SINGLE COMPUTER.
|
|
//
|
|
// CONTACT INFORMATION:
|
|
// support@codejock.com
|
|
// http://www.codejock.com
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "Common/XTPColorManager.h"
|
|
#include "Common/XTPSystemHelpers.h"
|
|
#include "Common/XTPDrawHelpers.h"
|
|
|
|
#include "../Defines.h"
|
|
#include "../Util/XTPGlobal.h"
|
|
#include "../Util/XTPControlTheme.h"
|
|
#include "XTPSplitterWnd.h"
|
|
#include "XTPSplitterWndTheme.h"
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Visual attributes and other constants
|
|
|
|
// HitTest return values (values and spacing between values is important)
|
|
enum HitTestValue
|
|
{
|
|
noHit = 0,
|
|
vSplitterBox = 1,
|
|
hSplitterBox = 2,
|
|
bothSplitterBox = 3, // just for keyboard
|
|
vSplitterBar1 = 101,
|
|
vSplitterBar15 = 115,
|
|
hSplitterBar1 = 201,
|
|
hSplitterBar15 = 215,
|
|
splitterIntersection1 = 301,
|
|
splitterIntersection225 = 525
|
|
};
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CXTPSplitterWnd
|
|
|
|
CXTPSplitterWnd::CXTPSplitterWnd()
|
|
: m_pTheme(NULL)
|
|
, m_nHiddenCol(-1)
|
|
, m_nHiddenRow(-1)
|
|
, m_bDotTracker(FALSE)
|
|
, m_bNoSize(FALSE)
|
|
, m_bFullDrag(FALSE)
|
|
, m_bShowBorder(TRUE)
|
|
, m_nFullDrag(-1)
|
|
, m_point(-1, -1)
|
|
, m_bClipStyles(FALSE)
|
|
{
|
|
m_cxSplitter = m_cySplitter = 6;
|
|
m_cxSplitterGap = m_cySplitterGap = 6;
|
|
|
|
// Get system settings for full drag.
|
|
::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS,
|
|
0, &m_bFullDrag, 0);
|
|
|
|
VERIFY(SetTheme(xtpControlThemeDefault));
|
|
|
|
}
|
|
|
|
CXTPSplitterWnd::~CXTPSplitterWnd()
|
|
{
|
|
CMDTARGET_RELEASE(m_pTheme);
|
|
}
|
|
|
|
IMPLEMENT_DYNAMIC(CXTPSplitterWnd, CSplitterWnd)
|
|
|
|
BEGIN_MESSAGE_MAP(CXTPSplitterWnd, CSplitterWnd)
|
|
//{{AFX_MSG_MAP(CXTPSplitterWnd)
|
|
ON_WM_MOUSEMOVE()
|
|
//}}AFX_MSG_MAP
|
|
ON_WM_NCHITTEST_EX()
|
|
ON_MESSAGE(WM_XTP_SETCONTROLTHEME, OnSetTheme)
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CXTPSplitterWnd message handlers
|
|
|
|
void CXTPSplitterWnd::RefreshMetrics()
|
|
{
|
|
if (m_pTheme)
|
|
m_pTheme->RefreshMetrics();
|
|
|
|
if (::IsWindow(m_hWnd))
|
|
RedrawWindow();
|
|
}
|
|
|
|
BOOL CXTPSplitterWnd::SetTheme(CXTPSplitterWndTheme* pTheme)
|
|
{
|
|
CMDTARGET_RELEASE(m_pTheme);
|
|
m_pTheme = pTheme;
|
|
|
|
RefreshMetrics();
|
|
|
|
return (m_pTheme != NULL);
|
|
}
|
|
|
|
BOOL CXTPSplitterWnd::SetTheme(XTPControlTheme eTheme)
|
|
{
|
|
CXTPSplitterWndTheme* pTheme = NULL;
|
|
|
|
switch (eTheme)
|
|
{
|
|
case xtpControlThemeOffice2000:
|
|
case xtpControlThemeOfficeXP:
|
|
case xtpControlThemeVisualStudio2005:
|
|
case xtpControlThemeVisualStudio2008:
|
|
pTheme = new CXTPSplitterWndThemeOfficeXP();
|
|
break;
|
|
|
|
case xtpControlThemeVisualStudio2010:
|
|
pTheme = new CXTPSplitterWndThemeVisualStudio2010();
|
|
break;
|
|
|
|
case xtpControlThemeOffice2003:
|
|
pTheme = new CXTPSplitterWndThemeOffice2003();
|
|
break;
|
|
|
|
case xtpControlThemeResource:
|
|
pTheme = new CXTPSplitterWndThemeResource();
|
|
break;
|
|
|
|
case xtpControlThemeDefault:
|
|
default:
|
|
pTheme = new CXTPSplitterWndTheme();
|
|
break;
|
|
}
|
|
|
|
return SetTheme(pTheme);
|
|
}
|
|
|
|
LRESULT CXTPSplitterWnd::OnSetTheme(WPARAM wParam, LPARAM /*lParam*/)
|
|
{
|
|
XTPControlTheme eTheme = (XTPControlTheme)wParam;
|
|
|
|
SetTheme(eTheme);
|
|
|
|
return 0;
|
|
}
|
|
|
|
BOOL CXTPSplitterWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
|
|
{
|
|
switch (message)
|
|
{
|
|
case WM_SETTINGCHANGE:
|
|
::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &m_bFullDrag, 0);
|
|
RefreshMetrics();
|
|
break;
|
|
|
|
case WM_SYSCOLORCHANGE:
|
|
RefreshMetrics();
|
|
break;
|
|
|
|
case WM_PRINTCLIENT:
|
|
PrintClient(CDC::FromHandle((HDC)wParam));
|
|
return TRUE;
|
|
|
|
case WM_LBUTTONDOWN:
|
|
m_htTrack = HitTest(CPoint((int)LOWORD(lParam), (int)HIWORD(lParam)));
|
|
break;
|
|
|
|
case WM_LBUTTONUP:
|
|
Invalidate();
|
|
break;
|
|
}
|
|
|
|
return CSplitterWnd::OnWndMsg(message, wParam, lParam, pResult);
|
|
}
|
|
|
|
void CXTPSplitterWnd::PrintClient(CDC* pDC)
|
|
{
|
|
if (pDC)
|
|
{
|
|
CXTPClientRect rClient(this);
|
|
rClient.InflateRect(-m_cxBorder, -m_cyBorder);
|
|
|
|
CRect rectInside;
|
|
GetInsideRect(rectInside);
|
|
|
|
// draw the splitter boxes
|
|
if (m_bHasVScroll && m_nRows < m_nMaxRows)
|
|
{
|
|
OnDrawSplitter(pDC, splitBox,
|
|
CRect(rectInside.right, rClient.top,
|
|
rClient.right, rClient.top + m_cySplitter));
|
|
}
|
|
|
|
if (m_bHasHScroll && m_nCols < m_nMaxCols)
|
|
{
|
|
OnDrawSplitter(pDC, splitBox,
|
|
CRect(rClient.left, rectInside.bottom,
|
|
rClient.left + m_cxSplitter, rClient.bottom));
|
|
}
|
|
|
|
// extend split bars to window border (past margins)
|
|
DrawAllSplitBars(pDC, rectInside.right, rectInside.bottom);
|
|
}
|
|
}
|
|
|
|
void CXTPSplitterWnd::ShowColumn()
|
|
{
|
|
ASSERT_VALID(this);
|
|
if (m_nCols == m_nMaxCols && m_nHiddenCol == -1)
|
|
{
|
|
return;
|
|
}
|
|
ASSERT(m_nHiddenCol != -1);
|
|
|
|
int nShowCol = m_nHiddenCol;
|
|
m_nHiddenCol = -1;
|
|
|
|
int cxNew = m_pColInfo[m_nCols].nCurSize;
|
|
m_nCols++; // add a column
|
|
|
|
ASSERT(m_nCols == m_nMaxCols);
|
|
|
|
int nCol;
|
|
|
|
// Show the hidden column
|
|
int nRow;
|
|
for (nRow = 0; nRow < m_nRows; ++nRow)
|
|
{
|
|
int nShowRow = m_nHiddenRow != -1 && m_nHiddenRow <= nRow ? nRow + 1 : nRow;
|
|
CWnd* pPaneShow = GetDlgItem(AFX_IDW_PANE_FIRST + nShowRow * 16 + m_nCols);
|
|
|
|
ASSERT(pPaneShow != NULL);
|
|
if (!pPaneShow)
|
|
return;
|
|
pPaneShow->ShowWindow(SW_SHOWNA);
|
|
|
|
for (nCol = m_nCols - 2; nCol >= nShowCol; --nCol)
|
|
{
|
|
CWnd* pPane = GetPane(nRow, nCol);
|
|
ASSERT(pPane != NULL);
|
|
if (!pPane)
|
|
return;
|
|
pPane->SetDlgCtrlID(IdFromRowCol(nRow, nCol + 1));
|
|
}
|
|
|
|
pPaneShow->SetDlgCtrlID(IdFromRowCol(nRow, nShowCol));
|
|
}
|
|
|
|
if (m_nHiddenRow != -1)
|
|
{
|
|
CWnd* pPaneHide = GetDlgItem(AFX_IDW_PANE_FIRST + m_nHiddenRow * 16 + m_nCols);
|
|
if (pPaneHide)
|
|
{
|
|
pPaneHide->SetDlgCtrlID(AFX_IDW_PANE_FIRST + m_nMaxRows * 16 + nShowCol);
|
|
}
|
|
}
|
|
|
|
// new panes have been created -- recalculate layout
|
|
for (nCol = nShowCol + 1; nCol < m_nCols; nCol++)
|
|
m_pColInfo[nCol].nIdealSize = m_pColInfo[nCol - 1].nCurSize;
|
|
|
|
m_pColInfo[nShowCol].nIdealSize = cxNew;
|
|
RecalcLayout();
|
|
}
|
|
|
|
void CXTPSplitterWnd::HideColumn(int nColHide)
|
|
{
|
|
ASSERT_VALID(this);
|
|
if (m_nHiddenCol != -1)
|
|
{
|
|
// return if the requested one is hidden
|
|
if (m_nHiddenCol == nColHide)
|
|
{
|
|
return;
|
|
}
|
|
ShowColumn();
|
|
}
|
|
ASSERT(m_nCols > 1);
|
|
ASSERT(nColHide < m_nCols);
|
|
ASSERT(m_nHiddenCol == -1);
|
|
m_nHiddenCol = nColHide;
|
|
|
|
// if the column has an active window -- change it
|
|
int nActiveRow, nActiveCol;
|
|
if (GetActivePane(&nActiveRow, &nActiveCol) != NULL)
|
|
{
|
|
if (nActiveCol == nColHide)
|
|
{
|
|
if (++nActiveCol >= m_nCols)
|
|
nActiveCol = 0;
|
|
SetActivePane(nActiveRow, nActiveCol);
|
|
}
|
|
}
|
|
|
|
// hide all column panes
|
|
int nRow;
|
|
for (nRow = 0; nRow < m_nRows; nRow++)
|
|
{
|
|
CWnd* pPaneHide = GetPane(nRow, nColHide);
|
|
ASSERT(pPaneHide != NULL);
|
|
if (!pPaneHide)
|
|
return;
|
|
pPaneHide->ShowWindow(SW_HIDE);
|
|
int nRowHide = m_nHiddenRow != -1 && m_nHiddenRow <= nRow ? nRow + 1 : nRow;
|
|
pPaneHide->SetDlgCtrlID(AFX_IDW_PANE_FIRST + nRowHide * 16 + m_nCols);
|
|
|
|
int nCol;
|
|
for (nCol = nColHide + 1; nCol < m_nCols; nCol++)
|
|
{
|
|
CWnd* pPane = GetPane(nRow, nCol);
|
|
ASSERT(pPane != NULL);
|
|
if (!pPane)
|
|
return;
|
|
|
|
pPane->SetDlgCtrlID(IdFromRowCol(nRow, nCol - 1));
|
|
}
|
|
}
|
|
|
|
m_nCols--;
|
|
m_pColInfo[m_nCols].nCurSize = m_pColInfo[nColHide].nCurSize;
|
|
RecalcLayout();
|
|
}
|
|
|
|
void CXTPSplitterWnd::ShowRow()
|
|
{
|
|
ASSERT_VALID(this);
|
|
if (m_nRows == m_nMaxRows && m_nHiddenRow == -1)
|
|
{
|
|
return;
|
|
}
|
|
ASSERT(m_nHiddenRow != -1);
|
|
|
|
int nShowRow = m_nHiddenRow;
|
|
m_nHiddenRow = -1;
|
|
|
|
int cyNew = m_pRowInfo[m_nRows].nCurSize;
|
|
m_nRows++; // add a nRow
|
|
|
|
ASSERT(m_nRows == m_nMaxRows);
|
|
|
|
int nRow;
|
|
|
|
// Show the hidden nRow
|
|
int nCol;
|
|
for (nCol = 0; nCol < m_nCols; ++nCol)
|
|
{
|
|
int nShowCol = m_nHiddenCol != -1 && m_nHiddenCol <= nCol ? nCol + 1 : nCol;
|
|
CWnd* pPaneShow = GetDlgItem(AFX_IDW_PANE_FIRST + m_nRows * 16 + nShowCol);
|
|
|
|
ASSERT(pPaneShow != NULL);
|
|
if (!pPaneShow)
|
|
return;
|
|
pPaneShow->ShowWindow(SW_SHOWNA);
|
|
|
|
for (nRow = m_nRows - 2; nRow >= nShowRow; --nRow)
|
|
{
|
|
CWnd* pPane = GetPane(nRow, nCol);
|
|
ASSERT(pPane != NULL);
|
|
if (!pPane)
|
|
return;
|
|
pPane->SetDlgCtrlID(IdFromRowCol(nRow + 1, nCol));
|
|
}
|
|
|
|
pPaneShow->SetDlgCtrlID(IdFromRowCol(nShowRow, nCol));
|
|
}
|
|
|
|
if (m_nHiddenCol != -1)
|
|
{
|
|
CWnd* pPaneHide = GetDlgItem(AFX_IDW_PANE_FIRST + m_nRows * 16 + m_nHiddenCol);
|
|
if (pPaneHide)
|
|
{
|
|
pPaneHide->SetDlgCtrlID(AFX_IDW_PANE_FIRST + nShowRow * 16 + m_nMaxCols);
|
|
}
|
|
}
|
|
|
|
// new panes have been created -- recalculate layout
|
|
for (nRow = nShowRow + 1; nRow < m_nRows; nRow++)
|
|
m_pRowInfo[nRow].nIdealSize = m_pRowInfo[nRow - 1].nCurSize;
|
|
|
|
m_pRowInfo[nShowRow].nIdealSize = cyNew;
|
|
RecalcLayout();
|
|
}
|
|
|
|
void CXTPSplitterWnd::HideRow(int nRowHide)
|
|
{
|
|
ASSERT_VALID(this);
|
|
if (m_nHiddenRow != -1)
|
|
{
|
|
// return if the requested one is hidden
|
|
if (m_nHiddenRow == nRowHide)
|
|
{
|
|
return;
|
|
}
|
|
ShowRow();
|
|
}
|
|
ASSERT(m_nRows > 1);
|
|
ASSERT(nRowHide < m_nRows);
|
|
ASSERT(m_nHiddenRow == -1);
|
|
m_nHiddenRow = nRowHide;
|
|
|
|
int nActiveRow, nActiveCol;
|
|
|
|
// if the nRow has an active window -- change it
|
|
if (GetActivePane(&nActiveRow, &nActiveCol) != NULL)
|
|
{
|
|
if (nActiveRow == nRowHide)
|
|
{
|
|
if (++nActiveRow >= m_nRows)
|
|
nActiveRow = 0;
|
|
SetActivePane(nActiveRow, nActiveCol);
|
|
}
|
|
}
|
|
|
|
// hide all nRow panes.
|
|
int nCol;
|
|
for (nCol = 0; nCol < m_nCols; ++nCol)
|
|
{
|
|
CWnd* pPaneHide = GetPane(nRowHide, nCol);
|
|
ASSERT(pPaneHide != NULL);
|
|
if (!pPaneHide)
|
|
return;
|
|
|
|
pPaneHide->ShowWindow(SW_HIDE);
|
|
int nColHide = m_nHiddenCol != -1 && m_nHiddenCol <= nCol ? nCol + 1 : nCol;
|
|
pPaneHide->SetDlgCtrlID(AFX_IDW_PANE_FIRST + m_nRows * 16 + nColHide);
|
|
|
|
int nRow;
|
|
for (nRow = nRowHide + 1; nRow < m_nRows; ++nRow)
|
|
{
|
|
CWnd* pPane = GetPane(nRow, nCol);
|
|
ASSERT(pPane != NULL);
|
|
if (!pPane)
|
|
return;
|
|
|
|
pPane->SetDlgCtrlID(IdFromRowCol(nRow-1, nCol));
|
|
}
|
|
}
|
|
|
|
m_nRows--;
|
|
m_pRowInfo[m_nRows].nCurSize = m_pRowInfo[nRowHide].nCurSize;
|
|
RecalcLayout();
|
|
}
|
|
|
|
BOOL CXTPSplitterWnd::SwitchView(int nRow, int nCol, CView* pNewView)
|
|
{
|
|
CView *pOldView = DYNAMIC_DOWNCAST(CView, GetPane(nRow, nCol));
|
|
ASSERT_KINDOF(CView, pOldView);
|
|
|
|
if (pOldView == pNewView)
|
|
return FALSE;
|
|
|
|
int nOldID = pOldView->GetDlgCtrlID();
|
|
int nNewID = pNewView->GetDlgCtrlID();
|
|
|
|
// hide the views.
|
|
pOldView->ShowWindow(SW_HIDE);
|
|
pNewView->ShowWindow(SW_HIDE);
|
|
|
|
// swap ids.
|
|
pOldView->SetDlgCtrlID(nNewID);
|
|
pNewView->SetDlgCtrlID(nOldID);
|
|
|
|
// show the views.
|
|
pOldView->ShowWindow(SW_SHOW);
|
|
pNewView->ShowWindow(SW_SHOW);
|
|
|
|
RecalcLayout();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
CView* CXTPSplitterWnd::ReplaceView(int nRow, int nCol, CView* pNewView)
|
|
{
|
|
CView* pOldView = DYNAMIC_DOWNCAST(CView, GetPane (nRow, nCol));
|
|
ASSERT_KINDOF (CView, pOldView);
|
|
|
|
if (pOldView == pNewView)
|
|
return NULL;
|
|
|
|
int nCtrlID = pOldView->GetDlgCtrlID();
|
|
|
|
// swap ids.
|
|
pOldView->SetDlgCtrlID(0);
|
|
pNewView->SetDlgCtrlID(nCtrlID);
|
|
|
|
// show the views.
|
|
pOldView->ShowWindow(SW_HIDE);
|
|
pNewView->ShowWindow(SW_SHOW);
|
|
|
|
RecalcLayout();
|
|
|
|
return pOldView;
|
|
}
|
|
|
|
CView* CXTPSplitterWnd::ReplaceView(int nRow, int nCol, CRuntimeClass* pViewClass)
|
|
{
|
|
CView* pOldView = DYNAMIC_DOWNCAST(CView, GetPane (nRow, nCol));
|
|
ASSERT_KINDOF (CView, pOldView);
|
|
|
|
if (pOldView->IsKindOf(pViewClass))
|
|
return NULL;
|
|
|
|
// Get pointer to CDocument object so that it can be used in the creation
|
|
// process of the new view
|
|
CDocument* pDocument = pOldView->GetDocument();
|
|
|
|
int nCtrlID = pOldView->GetDlgCtrlID();
|
|
int nWidth, nHeight, nMinWidth, nMinHeight;
|
|
|
|
GetRowInfo(nRow, nWidth, nMinWidth);
|
|
GetColumnInfo(nCol, nHeight, nMinHeight);
|
|
|
|
// Create new view
|
|
CCreateContext contextT;
|
|
contextT.m_pLastView = NULL;
|
|
contextT.m_pCurrentDoc = pDocument;
|
|
contextT.m_pNewViewClass = pViewClass;
|
|
contextT.m_pNewDocTemplate = pDocument ? pDocument->GetDocTemplate() : NULL;
|
|
contextT.m_pCurrentFrame = NULL;
|
|
|
|
CWnd* pWnd = NULL;
|
|
TRY
|
|
{
|
|
pWnd = (CWnd*)pViewClass->CreateObject();
|
|
if (pWnd == NULL)
|
|
AfxThrowMemoryException();
|
|
}
|
|
CATCH_ALL(e)
|
|
{
|
|
TRACE0("Out of memory creating a view.\n");
|
|
// Note: DELETE_EXCEPTION(e) not required
|
|
return NULL;
|
|
}
|
|
END_CATCH_ALL
|
|
|
|
ASSERT_KINDOF(CWnd, pWnd);
|
|
ASSERT(pWnd->m_hWnd == NULL); // not yet created.
|
|
|
|
// Create with the right size (wrong position)
|
|
if (!pWnd->Create(NULL, NULL, WS_CHILD | WS_VISIBLE,
|
|
CRect(0, 0, 0, 0), this, nCtrlID, &contextT))
|
|
{
|
|
TRACE0("Warning: couldn't create new view.\n");
|
|
// pWnd will be cleaned up by PostNcDestroy
|
|
return NULL;
|
|
}
|
|
|
|
// Hide the old view.
|
|
pOldView->ShowWindow(SW_HIDE);
|
|
pOldView->SetDlgCtrlID(0);
|
|
|
|
SetRowInfo (nRow, nWidth, nMinWidth);
|
|
SetColumnInfo (nCol, nHeight, nMinHeight);
|
|
RecalcLayout ();
|
|
|
|
CView* pNewView = DYNAMIC_DOWNCAST (CView, GetPane (nRow, nCol));
|
|
ASSERT_KINDOF (CView, pNewView);
|
|
pNewView->OnInitialUpdate();
|
|
|
|
return pOldView;
|
|
}
|
|
|
|
void CXTPSplitterWnd::SetSplitCursor(int ht)
|
|
{
|
|
if (ht == vSplitterBox ||
|
|
ht >= vSplitterBar1 &&
|
|
ht <= vSplitterBar15)
|
|
{
|
|
SetCursor(XTPAuxData().hcurVSplitBar);
|
|
}
|
|
else if (
|
|
ht == hSplitterBox ||
|
|
ht >= hSplitterBar1 &&
|
|
ht <= hSplitterBar15)
|
|
{
|
|
SetCursor(XTPAuxData().hcurHSplitBar);
|
|
}
|
|
else
|
|
{
|
|
CSplitterWnd::SetSplitCursor(ht);
|
|
}
|
|
}
|
|
|
|
BOOL CXTPSplitterWnd::FullDragWindows() const
|
|
{
|
|
if (m_htTrack == hSplitterBox ||
|
|
m_htTrack == vSplitterBox)
|
|
{
|
|
// do not allow full drag when split box is tracking.
|
|
return FALSE;
|
|
}
|
|
|
|
if (m_nFullDrag == -1)
|
|
{
|
|
// use the system setting for full drag.
|
|
return m_bFullDrag;
|
|
}
|
|
else
|
|
{
|
|
// user defined setting for full drag.
|
|
return (BOOL)m_nFullDrag;
|
|
}
|
|
}
|
|
|
|
void CXTPSplitterWnd::DrawTracker(const CRect& rect, CBrush* pBrush)
|
|
{
|
|
// do not draw over top of horizontal split box.
|
|
if (m_htTrack == hSplitterBox)
|
|
{
|
|
if (rect.left < m_cxSplitter)
|
|
return;
|
|
}
|
|
|
|
// do not draw over top of vertical split box.
|
|
if (m_htTrack == vSplitterBox)
|
|
{
|
|
if (rect.top < m_cySplitter)
|
|
return;
|
|
}
|
|
|
|
ASSERT_VALID(this);
|
|
ASSERT(!rect.IsRectEmpty());
|
|
ASSERT((GetStyle() & WS_CLIPCHILDREN) == 0);
|
|
|
|
CClientDC dc(this);
|
|
int nSavedDC = dc.SaveDC();
|
|
|
|
if (m_bDotTracker)
|
|
{
|
|
CRect rc;
|
|
GetInsideRect(rc);
|
|
|
|
if (rect.Width() < rect.Height())
|
|
{
|
|
rc.right = rect.right;
|
|
}
|
|
else
|
|
{
|
|
rc.bottom = rect.top;
|
|
}
|
|
|
|
dc.DrawFocusRect(rc);
|
|
}
|
|
else
|
|
{
|
|
CRect rcTracker(&rect);
|
|
|
|
BOOL bVert = rcTracker.Height() > rcTracker.Width();
|
|
|
|
if (bVert)
|
|
{
|
|
if (rcTracker.Width() != 4)
|
|
{
|
|
rcTracker.left = rcTracker.right - 4;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (rcTracker.Height() != 4)
|
|
{
|
|
rcTracker.bottom = rcTracker.top + 4;
|
|
}
|
|
}
|
|
|
|
dc.SelectObject(pBrush);
|
|
dc.PatBlt(rcTracker.left, rcTracker.top, rcTracker.Width(), rcTracker.Height(), PATINVERT);
|
|
}
|
|
|
|
dc.RestoreDC(nSavedDC);
|
|
}
|
|
|
|
void CXTPSplitterWnd::OnInvertTracker(const CRect& rect)
|
|
{
|
|
if (!FullDragWindows())
|
|
{
|
|
if (m_pTheme)
|
|
{
|
|
DrawTracker(rect, m_pTheme->GetTrackBrush());
|
|
}
|
|
else
|
|
{
|
|
CSplitterWnd::OnInvertTracker(rect);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CXTPSplitterWnd::OnMouseMove(UINT nFlags, CPoint pt)
|
|
{
|
|
if (!FullDragWindows())
|
|
{
|
|
CSplitterWnd::OnMouseMove(nFlags, pt);
|
|
return;
|
|
}
|
|
|
|
if (GetCapture() != this)
|
|
StopTracking(FALSE);
|
|
|
|
if (m_bTracking)
|
|
{
|
|
// move tracker to current cursor position
|
|
|
|
pt.Offset(m_ptTrackOffset); // pt is the upper right of hit detect
|
|
// limit the point to the valid split range
|
|
if (pt.y < m_rectLimit.top)
|
|
pt.y = m_rectLimit.top;
|
|
else if (pt.y > m_rectLimit.bottom)
|
|
pt.y = m_rectLimit.bottom;
|
|
if (pt.x < m_rectLimit.left)
|
|
pt.x = m_rectLimit.left;
|
|
else if (pt.x > m_rectLimit.right)
|
|
pt.x = m_rectLimit.right;
|
|
|
|
if (m_htTrack == vSplitterBox ||
|
|
m_htTrack >= vSplitterBar1 && m_htTrack <= vSplitterBar15)
|
|
{
|
|
if (m_rectTracker.top != pt.y)
|
|
{
|
|
OnInvertTracker(m_rectTracker);
|
|
m_rectTracker.OffsetRect(0, pt.y - m_rectTracker.top);
|
|
OnInvertTracker(m_rectTracker);
|
|
}
|
|
}
|
|
else if (m_htTrack == hSplitterBox ||
|
|
m_htTrack >= hSplitterBar1 && m_htTrack <= hSplitterBar15)
|
|
{
|
|
if (m_rectTracker.left != pt.x)
|
|
{
|
|
OnInvertTracker(m_rectTracker);
|
|
m_rectTracker.OffsetRect(pt.x - m_rectTracker.left, 0);
|
|
OnInvertTracker(m_rectTracker);
|
|
}
|
|
}
|
|
else if (m_htTrack == bothSplitterBox ||
|
|
(m_htTrack >= splitterIntersection1 &&
|
|
m_htTrack <= splitterIntersection225))
|
|
{
|
|
if (m_rectTracker.top != pt.y)
|
|
{
|
|
OnInvertTracker(m_rectTracker);
|
|
m_rectTracker.OffsetRect(0, pt.y - m_rectTracker.top);
|
|
OnInvertTracker(m_rectTracker);
|
|
}
|
|
if (m_rectTracker2.left != pt.x)
|
|
{
|
|
OnInvertTracker(m_rectTracker2);
|
|
m_rectTracker2.OffsetRect(pt.x - m_rectTracker2.left, 0);
|
|
OnInvertTracker(m_rectTracker2);
|
|
}
|
|
}
|
|
|
|
StopTracking(TRUE);
|
|
StartTracking(HitTest(pt));
|
|
|
|
if (m_point != pt)
|
|
{
|
|
RedrawWindow(NULL, NULL,
|
|
RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE);
|
|
m_point = pt;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// simply hit-test and set appropriate cursor
|
|
|
|
int ht = HitTest(pt);
|
|
SetSplitCursor(ht);
|
|
}
|
|
}
|
|
|
|
void CXTPSplitterWnd::StartTracking(int ht)
|
|
{
|
|
if (!FullDragWindows())
|
|
{
|
|
CSplitterWnd::StartTracking(ht);
|
|
return;
|
|
}
|
|
|
|
ASSERT_VALID(this);
|
|
if (ht == noHit)
|
|
return;
|
|
|
|
// GetHitRect will restrict 'm_rectLimit' as appropriate
|
|
GetInsideRect(m_rectLimit);
|
|
|
|
if (ht >= splitterIntersection1 && ht <= splitterIntersection225)
|
|
{
|
|
// split two directions (two tracking rectangles)
|
|
int row = (ht - splitterIntersection1) / 15;
|
|
int col = (ht - splitterIntersection1) % 15;
|
|
|
|
GetHitRect(row + vSplitterBar1, m_rectTracker);
|
|
int yTrackOffset = m_ptTrackOffset.y;
|
|
m_bTracking2 = TRUE;
|
|
GetHitRect(col + hSplitterBar1, m_rectTracker2);
|
|
m_ptTrackOffset.y = yTrackOffset;
|
|
}
|
|
else if (ht == bothSplitterBox)
|
|
{
|
|
// hit on splitter boxes (for keyboard)
|
|
GetHitRect(vSplitterBox, m_rectTracker);
|
|
int yTrackOffset = m_ptTrackOffset.y;
|
|
m_bTracking2 = TRUE;
|
|
GetHitRect(hSplitterBox, m_rectTracker2);
|
|
m_ptTrackOffset.y = yTrackOffset;
|
|
|
|
// center it
|
|
m_rectTracker.OffsetRect(0, m_rectLimit.Height()/2);
|
|
m_rectTracker2.OffsetRect(m_rectLimit.Width()/2, 0);
|
|
}
|
|
else
|
|
{
|
|
// only hit one bar
|
|
GetHitRect(ht, m_rectTracker);
|
|
}
|
|
|
|
// set capture
|
|
SetCapture();
|
|
|
|
// set tracking state and appropriate cursor
|
|
m_bTracking = TRUE;
|
|
m_htTrack = ht;
|
|
SetSplitCursor(ht);
|
|
}
|
|
|
|
void CXTPSplitterWnd::StopTracking(BOOL bAccept)
|
|
{
|
|
if (!FullDragWindows())
|
|
{
|
|
CSplitterWnd::StopTracking(bAccept);
|
|
return;
|
|
}
|
|
|
|
ASSERT_VALID(this);
|
|
|
|
if (!m_bTracking)
|
|
return;
|
|
|
|
ReleaseCapture();
|
|
|
|
// erase tracker rectangle
|
|
OnInvertTracker(m_rectTracker);
|
|
if (m_bTracking2)
|
|
OnInvertTracker(m_rectTracker2);
|
|
m_bTracking = m_bTracking2 = FALSE;
|
|
|
|
// save old active view
|
|
CWnd* pOldActiveView = GetActivePane();
|
|
|
|
// m_rectTracker is set to the new splitter position (without border)
|
|
// (so, adjust relative to where the border will be)
|
|
m_rectTracker.OffsetRect(-CX_BORDER , -CY_BORDER);
|
|
m_rectTracker2.OffsetRect(-CX_BORDER, -CY_BORDER);
|
|
|
|
if (bAccept)
|
|
{
|
|
if (m_htTrack == vSplitterBox)
|
|
{
|
|
SplitRow(m_rectTracker.top);
|
|
}
|
|
else if (m_htTrack >= vSplitterBar1 && m_htTrack <= vSplitterBar15)
|
|
{
|
|
// set row height
|
|
TrackRowSize(m_rectTracker.top, m_htTrack - vSplitterBar1);
|
|
RecalcLayout();
|
|
}
|
|
else if (m_htTrack == hSplitterBox)
|
|
{
|
|
SplitColumn(m_rectTracker.left);
|
|
}
|
|
else if (m_htTrack >= hSplitterBar1 && m_htTrack <= hSplitterBar15)
|
|
{
|
|
// set column width
|
|
TrackColumnSize(m_rectTracker.left, m_htTrack - hSplitterBar1);
|
|
RecalcLayout();
|
|
}
|
|
else if (m_htTrack >= splitterIntersection1 &&
|
|
m_htTrack <= splitterIntersection225)
|
|
{
|
|
// set row height and column width
|
|
int row = (m_htTrack - splitterIntersection1) / 15;
|
|
int col = (m_htTrack - splitterIntersection1) % 15;
|
|
|
|
TrackRowSize(m_rectTracker.top, row);
|
|
TrackColumnSize(m_rectTracker2.left, col);
|
|
RecalcLayout();
|
|
}
|
|
else if (m_htTrack == bothSplitterBox)
|
|
{
|
|
// rectTracker is vSplitter (splits rows)
|
|
// rectTracker2 is hSplitter (splits cols)
|
|
SplitRow(m_rectTracker.top);
|
|
SplitColumn(m_rectTracker2.left);
|
|
}
|
|
}
|
|
|
|
if (pOldActiveView == GetActivePane())
|
|
{
|
|
if (pOldActiveView != NULL)
|
|
{
|
|
SetActivePane(-1, -1, pOldActiveView); // re-activate
|
|
}
|
|
}
|
|
}
|
|
|
|
LRESULT CXTPSplitterWnd::OnNcHitTest(CPoint point)
|
|
{
|
|
// If m_bNoSize is TRUE, just return a border
|
|
// hit so can at least activate the app if needed.
|
|
if (m_bNoSize)
|
|
{
|
|
return HTBORDER;
|
|
}
|
|
return (LRESULT)CSplitterWnd::OnNcHitTest(point);
|
|
}
|
|
|
|
void CXTPSplitterWnd::OnDrawSplitter(CDC* pDC, ESplitType nType, const CRect& rectArg)
|
|
{
|
|
if (m_pTheme)
|
|
{
|
|
// if NULL just invalidate
|
|
if (pDC == NULL)
|
|
{
|
|
RedrawWindow(rectArg, NULL, RDW_INVALIDATE | RDW_NOCHILDREN);
|
|
}
|
|
else
|
|
{
|
|
ASSERT_VALID(pDC);
|
|
m_pTheme->DrawSplitter(pDC, this, nType, rectArg);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if no theme defined do default drawing.
|
|
CSplitterWnd::OnDrawSplitter(pDC, nType, rectArg);
|
|
}
|
|
}
|
|
|
|
void CXTPSplitterWnd::SetActivePane(int row, int col, CWnd* pWnd/*= NULL*/)
|
|
{
|
|
// set the focus to the pane
|
|
CWnd* pPane = pWnd == NULL ? GetPane(row, col) : pWnd;
|
|
if (pPane->IsKindOf(RUNTIME_CLASS(CView)))
|
|
{
|
|
CFrameWnd* pFrameWnd = GetParentFrame();
|
|
ASSERT_VALID(pFrameWnd);
|
|
pFrameWnd->SetActiveView((CView*)pPane);
|
|
}
|
|
else
|
|
{
|
|
pPane->SetFocus();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
// Note: The following functions are deprecated and could be removed
|
|
// in a future release.
|
|
//-----------------------------------------------------------------------
|
|
|
|
void CXTPSplitterWnd::SetFullDrag(BOOL bFullDrag)
|
|
{
|
|
TRACE0("Member function is deprecated use EnableFullDrag() instead.\n");
|
|
|
|
EnableFullDrag((int)bFullDrag);
|
|
}
|
|
|
|
void CXTPSplitterWnd::SetSplitterStyle(DWORD dwxStyle)
|
|
{
|
|
TRACE0("CXTPSplitterWnd::SetSplitterStyle is deprecated use EnableFullDrag(), EnableDotTracker() or EnableNoSize() instead.\n");
|
|
|
|
EnableNoSize(dwxStyle & XTP_SPLIT_NOSIZE ? TRUE : FALSE);
|
|
EnableFullDrag(dwxStyle & XTP_SPLIT_NOFULLDRAG ? 0 : -1);
|
|
EnableDotTracker(dwxStyle & XTP_SPLIT_DOTTRACKER ? TRUE : FALSE);
|
|
EnableBorder(dwxStyle & XTP_SPLIT_NOBORDER ? FALSE : TRUE);
|
|
}
|
|
|
|
DWORD CXTPSplitterWnd::GetSplitterStyle()
|
|
{
|
|
TRACE0("CXTPSplitterWnd::GetSplitterStyle is deprecated.\n");
|
|
|
|
DWORD dwStyle = 0L;
|
|
|
|
if (m_nFullDrag == 0)
|
|
dwStyle |= XTP_SPLIT_NOFULLDRAG;
|
|
|
|
if (m_bDotTracker)
|
|
dwStyle |= XTP_SPLIT_DOTTRACKER;
|
|
|
|
if (m_bNoSize)
|
|
dwStyle |= XTP_SPLIT_NOSIZE;
|
|
|
|
if (!m_bShowBorder)
|
|
dwStyle |= XTP_SPLIT_NOBORDER;
|
|
|
|
return dwStyle;
|
|
}
|
|
|
|
void CXTPSplitterWnd::EnableFlatLook(BOOL bFlatSplitter)
|
|
{
|
|
TRACE0("CXTPSplitterWnd::EnableFlatLook is deprecated use SetTheme() instead.\n");
|
|
|
|
SetTheme(bFlatSplitter ? xtpControlThemeOfficeXP : xtpControlThemeOffice2000);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// CXTPSplitterWndEx
|
|
//
|
|
|
|
IMPLEMENT_DYNAMIC(CXTPSplitterWndEx, CXTPSplitterWnd)
|
|
|
|
BEGIN_MESSAGE_MAP(CXTPSplitterWndEx, CXTPSplitterWnd)
|
|
//{{AFX_MSG_MAP(CXTPSplitterWndEx)
|
|
ON_WM_ERASEBKGND()
|
|
ON_WM_PAINT()
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
CXTPSplitterWndEx::CXTPSplitterWndEx()
|
|
{
|
|
m_cxBorder = 0;
|
|
m_cyBorder = 0;
|
|
m_cxSplitter = 4;
|
|
m_cySplitter = 4;
|
|
m_cxSplitterGap = 4;
|
|
m_cySplitterGap = 4;
|
|
m_cyTopBorderGap = 6;
|
|
m_bShowTopBorder = true;
|
|
}
|
|
|
|
CXTPSplitterWndEx::~CXTPSplitterWndEx()
|
|
{
|
|
|
|
}
|
|
|
|
void CXTPSplitterWndEx::OnDrawSplitter(CDC* pDC, ESplitType nType, const CRect& rectArg)
|
|
{
|
|
COLORREF clr3DFace = GetTheme()->m_crBack;
|
|
COLORREF clr3DShadow = GetTheme()->m_crInnerBorder;
|
|
|
|
if (pDC == NULL)
|
|
{
|
|
RedrawWindow(rectArg, NULL, RDW_INVALIDATE | RDW_NOCHILDREN);
|
|
return;
|
|
}
|
|
ASSERT_VALID(pDC);
|
|
CRect rect = rectArg;
|
|
switch (nType)
|
|
{
|
|
case splitBorder:
|
|
return;
|
|
case splitBox:
|
|
pDC->Draw3dRect(rect, clr3DFace, GetXtremeColor(COLOR_WINDOWFRAME));
|
|
rect.InflateRect(-CX_BORDER, -CY_BORDER);
|
|
pDC->Draw3dRect(rect, GetXtremeColor(COLOR_3DHILIGHT), clr3DShadow);
|
|
rect.InflateRect(-CX_BORDER, -CY_BORDER);
|
|
break;
|
|
}
|
|
|
|
pDC->FillSolidRect(rect, clr3DFace);
|
|
}
|
|
|
|
// Generic routine:
|
|
// for X direction: pInfo = m_pColInfo, nMax = m_nMaxCols, nSize = cx
|
|
// for Y direction: pInfo = m_pRowInfo, nMax = m_nMaxRows, nSize = cy
|
|
void CXTPSplitterWndEx::LayoutRowCol(CSplitterWnd::CRowColInfo* pInfoArray,
|
|
int nMax, int nSize, int nSizeSplitter)
|
|
{
|
|
ASSERT(pInfoArray != NULL);
|
|
ASSERT(nMax > 0);
|
|
ASSERT(nSizeSplitter > 0);
|
|
|
|
if (!pInfoArray)
|
|
return;
|
|
|
|
CSplitterWnd::CRowColInfo* pInfo = NULL;
|
|
int i;
|
|
|
|
if (nSize < 0)
|
|
nSize = 0; // if really too small, layout as zero size
|
|
|
|
// start with ideal sizes
|
|
for (i = 0, pInfo = pInfoArray; i < nMax-1; i++, pInfo++)
|
|
{
|
|
if (pInfo->nIdealSize < pInfo->nMinSize)
|
|
pInfo->nIdealSize = 0; // too small to see
|
|
pInfo->nCurSize = pInfo->nIdealSize;
|
|
}
|
|
if (!pInfo)
|
|
return;
|
|
|
|
pInfo->nCurSize = INT_MAX; // last row/column takes the rest
|
|
|
|
for (i = 0, pInfo = pInfoArray; i < nMax; i++, pInfo++)
|
|
{
|
|
ASSERT(nSize >= 0);
|
|
if (nSize == 0)
|
|
{
|
|
// no more room (set pane to be invisible)
|
|
pInfo->nCurSize = 0;
|
|
continue; // don't worry about splitters
|
|
}
|
|
else if (nSize < pInfo->nMinSize && i != 0)
|
|
{
|
|
// additional panes below the recommended minimum size
|
|
// aren't shown and the size goes to the previous pane
|
|
pInfo->nCurSize = 0;
|
|
|
|
// previous pane already has room for splitter + border
|
|
// add remaining size and remove the extra border
|
|
ASSERT(CX_BORDER * 2 == CY_BORDER * 2);
|
|
(pInfo-1)->nCurSize += nSize + CX_BORDER * 2;
|
|
nSize = 0;
|
|
}
|
|
else
|
|
{
|
|
// otherwise we can add the second pane
|
|
ASSERT(nSize > 0);
|
|
if (pInfo->nCurSize == 0)
|
|
{
|
|
// too small to see
|
|
if (i != 0)
|
|
pInfo->nCurSize = 0;
|
|
}
|
|
else if (nSize < pInfo->nCurSize)
|
|
{
|
|
// this row/col won't fit completely - make as small as possible
|
|
pInfo->nCurSize = nSize;
|
|
nSize = 0;
|
|
}
|
|
else
|
|
{
|
|
// can fit everything
|
|
nSize -= pInfo->nCurSize;
|
|
}
|
|
}
|
|
|
|
// see if we should add a splitter
|
|
ASSERT(nSize >= 0);
|
|
if (i != nMax - 1)
|
|
{
|
|
// should have a splitter
|
|
if (nSize > nSizeSplitter)
|
|
{
|
|
nSize -= nSizeSplitter; // leave room for splitter + border
|
|
ASSERT(nSize > 0);
|
|
}
|
|
else
|
|
{
|
|
// not enough room - add left over less splitter size
|
|
ASSERT(CX_BORDER * 2 == CY_BORDER * 2);
|
|
pInfo->nCurSize += nSize;
|
|
if (pInfo->nCurSize > (nSizeSplitter - CX_BORDER * 2))
|
|
pInfo->nCurSize -= (nSizeSplitter - CY_BORDER * 2);
|
|
nSize = 0;
|
|
}
|
|
}
|
|
}
|
|
ASSERT(nSize == 0); // all space should be allocated
|
|
}
|
|
|
|
// repositions client area of specified window
|
|
// assumes everything has WS_BORDER or is inset like it does
|
|
// (includes scroll bars)
|
|
void CXTPSplitterWndEx::DeferClientPos(AFX_SIZEPARENTPARAMS* lpLayout,
|
|
CWnd* pWnd, int x, int y, int cx, int cy, BOOL bScrollBar)
|
|
{
|
|
ASSERT(pWnd != NULL);
|
|
if (!pWnd)
|
|
return;
|
|
ASSERT(pWnd->m_hWnd != NULL);
|
|
|
|
if (bScrollBar)
|
|
{
|
|
// if there is enough room, draw scroll bar without border
|
|
// if there is not enough room, set the WS_BORDER bit so that
|
|
// we will at least get a proper border drawn
|
|
BOOL bNeedBorder = (cx <= CX_BORDER || cy <= CY_BORDER);
|
|
pWnd->ModifyStyle(bNeedBorder ? 0 : WS_BORDER,
|
|
bNeedBorder ? WS_BORDER : 0);
|
|
}
|
|
CRect rect(x, y, x + cx, y + cy);
|
|
|
|
// adjust for border size (even if zero client size)
|
|
|
|
// adjust for 3d border (splitter windows have implied border)
|
|
if ((pWnd->GetExStyle() & WS_EX_CLIENTEDGE) ||
|
|
pWnd->IsKindOf(RUNTIME_CLASS(CSplitterWnd)))
|
|
rect.InflateRect(CX_BORDER * 2, CY_BORDER * 2);
|
|
|
|
// first check if the new rectangle is the same as the current
|
|
CRect rectOld;
|
|
pWnd->GetWindowRect(rectOld);
|
|
pWnd->GetParent()->ScreenToClient(&rectOld);
|
|
if (rect != rectOld)
|
|
AfxRepositionWindow(lpLayout, pWnd->m_hWnd, rect);
|
|
}
|
|
|
|
void CXTPSplitterWndEx::RecalcLayout()
|
|
{
|
|
ASSERT_VALID(this);
|
|
ASSERT(m_nRows > 0 && m_nCols > 0); // must have at least one pane
|
|
|
|
CRect rectClient;
|
|
GetClientRect(rectClient);
|
|
rectClient.InflateRect(-m_cxBorder, -m_cyBorder);
|
|
rectClient.top += m_cyTopBorderGap;
|
|
|
|
CRect rectInside;
|
|
GetInsideRect(rectInside);
|
|
|
|
// layout columns (restrict to possible sizes)
|
|
LayoutRowCol(m_pColInfo, m_nCols, rectInside.Width(), m_cxSplitterGap);
|
|
LayoutRowCol(m_pRowInfo, m_nRows, rectInside.Height(), m_cySplitterGap);
|
|
|
|
// adjust the panes (and optionally scroll bars)
|
|
|
|
// give the hint for the maximum number of HWNDs
|
|
AFX_SIZEPARENTPARAMS layout;
|
|
layout.hDWP = ::BeginDeferWindowPos((m_nCols + 1) * (m_nRows + 1) + 1);
|
|
|
|
// size of scrollbars
|
|
int cx = (rectClient.right - rectInside.right);
|
|
int cy = (rectClient.bottom - rectInside.bottom);
|
|
|
|
// reposition size box
|
|
if (m_bHasHScroll && m_bHasVScroll)
|
|
{
|
|
CWnd* pScrollBar = GetDlgItem(AFX_IDW_SIZE_BOX);
|
|
ASSERT(pScrollBar != NULL);
|
|
|
|
// fix style if necessary
|
|
BOOL bSizingParent = (GetSizingParent() != NULL);
|
|
// modifyStyle returns TRUE if style changes
|
|
if (pScrollBar->ModifyStyle(SBS_SIZEGRIP | SBS_SIZEBOX,
|
|
bSizingParent ? SBS_SIZEGRIP : SBS_SIZEBOX))
|
|
pScrollBar->Invalidate();
|
|
pScrollBar->EnableWindow(bSizingParent);
|
|
|
|
// reposition the size box
|
|
DeferClientPos(&layout, pScrollBar,
|
|
rectInside.right, rectInside.bottom, cx, cy, TRUE);
|
|
}
|
|
|
|
// reposition scroll bars
|
|
if (m_bHasHScroll)
|
|
{
|
|
int cxSplitterBox = m_cxSplitter;// split box bigger
|
|
int x = rectClient.left;
|
|
int y = rectInside.bottom;
|
|
int col;
|
|
for (col = 0; col < m_nCols; col++)
|
|
{
|
|
CWnd* pScrollBar = GetDlgItem(AFX_IDW_HSCROLL_FIRST + col);
|
|
ASSERT(pScrollBar != NULL);
|
|
int cxColumn = m_pColInfo[col].nCurSize;
|
|
if (col == 0 && m_nCols < m_nMaxCols)
|
|
x += cxSplitterBox, cxColumn -= cxSplitterBox;
|
|
DeferClientPos(&layout, pScrollBar, x, y, cxColumn, cy, TRUE);
|
|
x += cxColumn + m_cxSplitterGap;
|
|
}
|
|
}
|
|
|
|
if (m_bHasVScroll)
|
|
{
|
|
int cySplitterBox = m_cySplitter;// split box bigger
|
|
int x = rectInside.right;
|
|
int y = rectClient.top;
|
|
int row;
|
|
for (row = 0; row < m_nRows; row++)
|
|
{
|
|
CWnd* pScrollBar = GetDlgItem(AFX_IDW_VSCROLL_FIRST + row);
|
|
ASSERT(pScrollBar != NULL);
|
|
int cyColumn = m_pRowInfo[row].nCurSize;
|
|
if (row == 0 && m_nRows < m_nMaxRows)
|
|
y += cySplitterBox, cyColumn -= cySplitterBox;
|
|
DeferClientPos(&layout, pScrollBar, x, y, cx, cyColumn, TRUE);
|
|
y += cyColumn + m_cySplitterGap;
|
|
}
|
|
}
|
|
|
|
//BLOCK: Reposition all the panes
|
|
{
|
|
int x = rectClient.left;
|
|
int col;
|
|
for (col = 0; col < m_nCols; col++)
|
|
{
|
|
int cxColumn = m_pColInfo[col].nCurSize;
|
|
int y = rectClient.top;
|
|
int row;
|
|
for (row = 0; row < m_nRows; row++)
|
|
{
|
|
int cyColumn = m_pRowInfo[row].nCurSize;
|
|
CWnd* pWnd = GetPane(row, col);
|
|
DeferClientPos(&layout, pWnd, x, y, cxColumn, cyColumn, FALSE);
|
|
y += cyColumn + m_cySplitterGap;
|
|
}
|
|
x += cxColumn + m_cxSplitterGap;
|
|
}
|
|
}
|
|
|
|
// move and resize all the windows at once!
|
|
if (layout.hDWP == NULL || !::EndDeferWindowPos(layout.hDWP))
|
|
TRACE0("Warning: DeferWindowPos failed - low system resources.\n");
|
|
|
|
// invalidate all the splitter bars (with NULL pDC)
|
|
DrawAllSplitBars(NULL, rectInside.right, rectInside.bottom);
|
|
}
|
|
|
|
void CXTPSplitterWndEx::GetInsideRect(CRect& rect) const
|
|
{
|
|
CSplitterWnd::GetInsideRect(rect);
|
|
rect.top += m_cyTopBorderGap;
|
|
}
|
|
|
|
void CXTPSplitterWndEx::OnPaint()
|
|
{
|
|
CSplitterWnd::OnPaint();
|
|
|
|
if (m_bShowTopBorder)
|
|
{
|
|
CClientDC dc(this);
|
|
|
|
int iSavedDC = dc.SaveDC();
|
|
|
|
CRect rectClient;
|
|
GetClientRect(rectClient);
|
|
|
|
if (m_pTheme->GetThemeStyle() == xtpControlThemeDefault)
|
|
{
|
|
CPen penShadow(PS_SOLID, 1, GetXtremeColor(COLOR_3DSHADOW));
|
|
dc.SelectObject(&penShadow);
|
|
dc.MoveTo(rectClient.left, rectClient.top);
|
|
dc.LineTo(rectClient.right, rectClient.top);
|
|
}
|
|
|
|
CPen penHilight(PS_SOLID, 1, GetXtremeColor(COLOR_3DHILIGHT));
|
|
dc.SelectObject(&penHilight);
|
|
dc.MoveTo(rectClient.left, rectClient.top + 1);
|
|
dc.LineTo(rectClient.right, rectClient.top + 1);
|
|
|
|
dc.RestoreDC(iSavedDC);
|
|
}
|
|
}
|
|
|
|
BOOL CXTPSplitterWndEx::OnEraseBkgnd(CDC* pDC)
|
|
{
|
|
CRect rectClient;
|
|
GetClientRect(rectClient);
|
|
rectClient.InflateRect(-m_cxBorder, -m_cyBorder);
|
|
rectClient.bottom = rectClient.top + m_cyTopBorderGap;
|
|
|
|
COLORREF clr3DFace = GetTheme()->m_crBack;
|
|
pDC->FillSolidRect(rectClient, clr3DFace);
|
|
|
|
return TRUE;
|
|
}
|