// FX_SplitterWnd.cpp: implementation of the CFX_SplitterWnd class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" //#include "teststatusbar.h" #include "FX_SplitterWnd.h" #include #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); }