blob: 4024bb5c912408cf9e5c428fb62e98aca34419ee [file] [log] [blame]
// FX_SplitterWnd.cpp: implementation of the CFX_SplitterWnd class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
//#include "teststatusbar.h"
#include "FX_SplitterWnd.h"
#include <afxpriv.h>
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CFX_SplitterWnd::CFX_SplitterWnd()
{
m_cxSplitter = m_cySplitter = 4 + 1 + 1;
m_cxBorderShare = m_cyBorderShare = 0;
m_cxSplitterGap = m_cySplitterGap = 4 + 1 + 1;
m_cxBorder = m_cyBorder = 1;
m_nHidedCol = -1;
m_bBarLocked = FALSE;
}
CFX_SplitterWnd::~CFX_SplitterWnd()
{
}
BEGIN_MESSAGE_MAP(CFX_SplitterWnd, CSplitterWnd)
//{{AFX_MSG_MAP(CFX_SplitterWnd)
ON_WM_LBUTTONDOWN()
ON_WM_MOUSEMOVE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
void CFX_SplitterWnd::OnDrawSplitter(CDC *pDC,ESplitType nType,const CRect &rectArg)
{
if((nType != splitBorder) || (pDC == NULL))
{
CSplitterWnd::OnDrawSplitter(pDC, nType, rectArg);
return;
}
pDC->Draw3dRect(rectArg, GetSysColor(COLOR_BTNSHADOW), GetSysColor(COLOR_BTNHIGHLIGHT));
}
void CFX_SplitterWnd::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);
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;
for (int col = 0; col < m_nCols; col++)
{
CWnd* pScrollBar = GetDlgItem(AFX_IDW_HSCROLL_FIRST + col);
ASSERT(pScrollBar != NULL);
int cx = m_pColInfo[col].nCurSize;
if (col == 0 && m_nCols < m_nMaxCols)
x += cxSplitterBox, cx -= cxSplitterBox;
DeferClientPos(&layout, pScrollBar, x, y, cx, cy, TRUE);
x += cx + m_cxSplitterGap;
}
}
if (m_bHasVScroll)
{
int cySplitterBox = m_cySplitter;// split box bigger
int x = rectInside.right;
int y = rectClient.top;
for (int row = 0; row < m_nRows; row++)
{
CWnd* pScrollBar = GetDlgItem(AFX_IDW_VSCROLL_FIRST + row);
ASSERT(pScrollBar != NULL);
int cy = m_pRowInfo[row].nCurSize;
if (row == 0 && m_nRows < m_nMaxRows)
y += cySplitterBox, cy -= cySplitterBox;
DeferClientPos(&layout, pScrollBar, x, y, cx, cy, TRUE);
y += cy + m_cySplitterGap;
}
}
//BLOCK: Reposition all the panes
{
int x = rectClient.left;
for (int col = 0; col < m_nCols; col++)
{
int cx = m_pColInfo[col].nCurSize;
int y = rectClient.top;
for (int row = 0; row < m_nRows; row++)
{
int cy = m_pRowInfo[row].nCurSize;
CWnd* pWnd = GetPane(row, col);
DeferClientPos(&layout, pWnd, x, y, cx, cy, FALSE);
y += cy + m_cySplitterGap;
}
x += cx + 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 CFX_SplitterWnd::DeferClientPos(AFX_SIZEPARENTPARAMS *lpLayout,CWnd *pWnd,int x,int y,int cx,int cy,BOOL bScrollBar)
{
ASSERT(pWnd != NULL);
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 <= 1 || cy <= 1);
pWnd->ModifyStyle(bNeedBorder ? 0 : 1, bNeedBorder ? 1 : 0);
}
CRect rect(x, y, x+cx, y+cy);
// adjust for 3d border (splitter windows have implied border)
if ((pWnd->GetExStyle() & WS_EX_CLIENTEDGE) || pWnd->IsKindOf(RUNTIME_CLASS(CSplitterWnd)))
{
rect.InflateRect(1, 1); // for proper draw CFlatSplitterWnd in view
// rect.InflateRect(afxData.cxBorder2, afxData.cyBorder2);
}
// 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 CFX_SplitterWnd::LayoutRowCol(CSplitterWnd::CRowColInfo *pInfoArray,int nMax,int nSize,int nSizeSplitter)
{
ASSERT(pInfoArray != NULL);
ASSERT(nMax > 0);
ASSERT(nSizeSplitter > 0);
CSplitterWnd::CRowColInfo* pInfo;
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;
}
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
(pInfo-1)->nCurSize += nSize + 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
pInfo->nCurSize += nSize;
if (pInfo->nCurSize > (nSizeSplitter - 2))
pInfo->nCurSize -= (nSizeSplitter - 2);
nSize = 0;
}
}
}
ASSERT(nSize == 0); // all space should be allocated
}
void CFX_SplitterWnd::HideColumn(int nCol)
{
if ( m_nHidedCol != -1 )
return;
ASSERT_VALID(this);
ASSERT(m_nCols > 1);
ASSERT(nCol < m_nCols);
ASSERT(m_nHidedCol == -1);
m_nHidedCol = nCol;
// if the column has an active window -- change it
int rowActive, colActive;
if (GetActivePane(&rowActive, &colActive) != NULL &&
colActive == nCol)
{
if (++colActive >= m_nCols)
colActive = 0;
SetActivePane(rowActive, colActive);
}
// hide all column panes
for (int row = 0; row < m_nRows; row++)
{
CWnd* pPaneHide = GetPane(row, nCol);
ASSERT(pPaneHide != NULL);
pPaneHide->ShowWindow(SW_HIDE);
pPaneHide->SetDlgCtrlID(
AFX_IDW_PANE_FIRST + row * 16 + m_nCols);
for (int col = nCol + 1; col < m_nCols; col++)
{
CWnd* pPane = GetPane(row, col);
ASSERT(pPane != NULL);
pPane->SetDlgCtrlID(IdFromRowCol(row, col - 1));
}
}
m_nCols--;
m_pColInfo[m_nCols].nCurSize = m_pColInfo[nCol].nCurSize;
RecalcLayout();
}
void CFX_SplitterWnd::ShowColumn()
{
if ( m_nHidedCol == -1 )
return;
ASSERT_VALID(this);
ASSERT(m_nCols < m_nMaxCols);
ASSERT(m_nHidedCol != -1);
int colNew = m_nHidedCol;
m_nHidedCol = -1;
int cxNew = m_pColInfo[m_nCols].nCurSize;
m_nCols++; // add a column
ASSERT(m_nCols == m_nMaxCols);
// fill the hided column
int col;
for (int row = 0; row < m_nRows; row++)
{
CWnd* pPaneShow = GetDlgItem(
AFX_IDW_PANE_FIRST + row * 16 + m_nCols);
ASSERT(pPaneShow != NULL);
pPaneShow->ShowWindow(SW_SHOWNA);
for (col = m_nCols - 2; col >= colNew; col--)
{
CWnd* pPane = GetPane(row, col);
ASSERT(pPane != NULL);
pPane->SetDlgCtrlID(IdFromRowCol(row, col + 1));
}
pPaneShow->SetDlgCtrlID(IdFromRowCol(row, colNew));
}
// new panes have been created -- recalculate layout
for (col = colNew + 1; col < m_nCols; col++)
m_pColInfo[col].nIdealSize = m_pColInfo[col - 1].nCurSize;
m_pColInfo[colNew].nIdealSize = cxNew;
RecalcLayout();
}
void CFX_SplitterWnd::OnLButtonDown(UINT nFlags, CPoint point)
{
if (!m_bBarLocked)
CSplitterWnd::OnLButtonDown(nFlags, point);
}
void CFX_SplitterWnd::OnMouseMove(UINT nFlags, CPoint point)
{
if (!m_bBarLocked)
CSplitterWnd::OnMouseMove(nFlags, point);
else
CWnd::OnMouseMove(nFlags, point);
}