home *** CD-ROM | disk | FTP | other *** search
- // This is a part of the Microsoft Foundation Classes C++ library.
- // Copyright (C) 1992-1998 Microsoft Corporation
- // All rights reserved.
- //
- // This source code is only intended as a supplement to the
- // Microsoft Foundation Classes Reference and related
- // electronic documentation provided with the library.
- // See these sources for detailed information regarding the
- // Microsoft Foundation Classes product.
-
- #include "stdafx.h"
-
- #ifdef AFX_CORE3_SEG
- #pragma code_seg(AFX_CORE3_SEG)
- #endif
-
- #ifdef _DEBUG
- #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
- };
-
- /////////////////////////////////////////////////////////////////////////////
- // CSplitterWnd
-
- BEGIN_MESSAGE_MAP(CSplitterWnd, CWnd)
- //{{AFX_MSG_MAP(CSplitterWnd)
- ON_WM_SETCURSOR()
- ON_WM_MOUSEMOVE()
- ON_WM_PAINT()
- ON_WM_LBUTTONDOWN()
- ON_WM_LBUTTONDBLCLK()
- ON_WM_LBUTTONUP()
- ON_WM_KEYDOWN()
- ON_WM_SIZE()
- ON_WM_HSCROLL()
- ON_WM_VSCROLL()
- ON_WM_NCCREATE()
- ON_WM_SYSCOMMAND()
- ON_WM_CANCELMODE()
- ON_MESSAGE_VOID(WM_DISPLAYCHANGE, OnDisplayChange)
- ON_MESSAGE_VOID(WM_WININICHANGE, OnDisplayChange)
- ON_MESSAGE_VOID(WM_SETTINGCHANGE, OnDisplayChange)
- ON_WM_MOUSEWHEEL()
- //}}AFX_MSG_MAP
- END_MESSAGE_MAP()
-
- /////////////////////////////////////////////////////////////////////////////
- // CSplitterWnd construction/destruction
-
- CSplitterWnd::CSplitterWnd()
- {
- AFX_ZERO_INIT_OBJECT(CWnd);
-
- // default splitter box/bar sizes (includes borders)
- if (!afxData.bWin4)
- {
- m_cxSplitter = m_cySplitter = 4;
- m_cxBorderShare = m_cyBorderShare = 1;
- m_cxSplitterGap = m_cySplitterGap = 4 + 1 + 1;
- ASSERT(m_cxBorder == 0 && m_cyBorder == 0);
- }
- else
- {
- m_cxSplitter = m_cySplitter = 3 + 2 + 2;
- m_cxBorderShare = m_cyBorderShare = 0;
- m_cxSplitterGap = m_cySplitterGap = 3 + 2 + 2;
- m_cxBorder = m_cyBorder = 2;
- }
-
- #ifdef _DEBUG
- if (GetSystemMetrics(SM_CXBORDER) != 1 ||
- GetSystemMetrics(SM_CYBORDER) != 1)
- {
- TRACE0("Warning: CSplitterWnd assumes 1 pixel border.\n");
- // will look ugly if borders are not 1 pixel wide and 1 pixel high
- }
- #endif
- }
-
- CSplitterWnd::~CSplitterWnd()
- {
- delete[] m_pRowInfo;
- delete[] m_pColInfo;
- }
-
- BOOL CSplitterWnd::Create(CWnd* pParentWnd,
- int nMaxRows, int nMaxCols, SIZE sizeMin,
- CCreateContext* pContext, DWORD dwStyle, UINT nID)
- {
- ASSERT(pParentWnd != NULL);
- ASSERT(sizeMin.cx > 0 && sizeMin.cy > 0); // minimum must be non-zero
-
- ASSERT(pContext != NULL);
- ASSERT(pContext->m_pNewViewClass != NULL);
- ASSERT(dwStyle & WS_CHILD);
- ASSERT(dwStyle & SPLS_DYNAMIC_SPLIT); // must have dynamic split behavior
-
- // Dynamic splitters are limited to 2x2
- ASSERT(nMaxRows >= 1 && nMaxRows <= 2);
- ASSERT(nMaxCols >= 1 && nMaxCols <= 2);
- ASSERT(nMaxCols > 1 || nMaxRows > 1); // 1x1 is not permitted
-
- m_nMaxRows = nMaxRows;
- m_nMaxCols = nMaxCols;
- ASSERT(m_nRows == 0 && m_nCols == 0); // none yet
- m_nRows = m_nCols = 1; // start off as 1x1
- if (!CreateCommon(pParentWnd, sizeMin, dwStyle, nID))
- return FALSE;
- ASSERT(m_nRows == 1 && m_nCols == 1); // still 1x1
-
- ASSERT(pContext->m_pNewViewClass->IsDerivedFrom(RUNTIME_CLASS(CWnd)));
- m_pDynamicViewClass = pContext->m_pNewViewClass;
- // save for later dynamic creations
-
- // add the first initial pane
- if (!CreateView(0, 0, m_pDynamicViewClass, sizeMin, pContext))
- {
- DestroyWindow(); // will clean up child windows
- return FALSE;
- }
- m_pColInfo[0].nIdealSize = sizeMin.cx;
- m_pRowInfo[0].nIdealSize = sizeMin.cy;
-
- return TRUE;
- }
-
- // simple "wiper" splitter
- BOOL CSplitterWnd::CreateStatic(CWnd* pParentWnd,
- int nRows, int nCols, DWORD dwStyle, UINT nID)
- {
- ASSERT(pParentWnd != NULL);
- ASSERT(nRows >= 1 && nRows <= 16);
- ASSERT(nCols >= 1 && nCols <= 16);
- ASSERT(nCols > 1 || nRows > 1); // 1x1 is not permitted
- ASSERT(dwStyle & WS_CHILD);
- ASSERT(!(dwStyle & SPLS_DYNAMIC_SPLIT)); // can't have dynamic split
-
- ASSERT(m_nRows == 0 && m_nCols == 0); // none yet
- m_nRows = m_nMaxRows = nRows;
- m_nCols = m_nMaxCols = nCols;
-
- // create with zero minimum pane size
- if (!CreateCommon(pParentWnd, CSize(0, 0), dwStyle, nID))
- return FALSE;
-
- // all panes must be created with explicit calls to CreateView
- return TRUE;
- }
-
- BOOL CSplitterWnd::CreateCommon(CWnd* pParentWnd,
- SIZE sizeMin, DWORD dwStyle, UINT nID)
- {
- ASSERT(pParentWnd != NULL);
- ASSERT(sizeMin.cx >= 0 && sizeMin.cy >= 0);
- ASSERT(dwStyle & WS_CHILD);
- ASSERT(nID != 0);
-
- ASSERT(m_pColInfo == NULL && m_pRowInfo == NULL); // only do once
- ASSERT(m_nMaxCols > 0 && m_nMaxRows > 0);
-
- // the Windows scroll bar styles bits turn on the smart scrollbars
- DWORD dwCreateStyle = dwStyle & ~(WS_HSCROLL|WS_VSCROLL);
- if (afxData.bWin4)
- dwCreateStyle &= ~WS_BORDER;
-
- VERIFY(AfxDeferRegisterClass(AFX_WNDMDIFRAME_REG));
-
- // create with the same wnd-class as MDI-Frame (no erase bkgnd)
- if (!CreateEx(0, _afxWndMDIFrame, NULL, dwCreateStyle, 0, 0, 0, 0,
- pParentWnd->m_hWnd, (HMENU)nID, NULL))
- return FALSE; // create invisible
-
- // attach the initial splitter parts
- TRY
- {
- m_pColInfo = new CRowColInfo[m_nMaxCols];
- for (int col = 0; col < m_nMaxCols; col++)
- {
- m_pColInfo[col].nMinSize = m_pColInfo[col].nIdealSize = sizeMin.cx;
- m_pColInfo[col].nCurSize = -1; // will be set in RecalcLayout
- }
- m_pRowInfo = new CRowColInfo[m_nMaxRows];
- for (int row = 0; row < m_nMaxRows; row++)
- {
- m_pRowInfo[row].nMinSize = m_pRowInfo[row].nIdealSize = sizeMin.cy;
- m_pRowInfo[row].nCurSize = -1; // will be set in RecalcLayout
- }
-
- // create scroll bars by setting the style
- SetScrollStyle(dwStyle);
- }
- CATCH_ALL(e)
- {
- DestroyWindow(); // will clean up child windows
- // Note: DELETE_EXCEPTION(e) not required
- return FALSE;
- }
- END_CATCH_ALL
-
- return TRUE;
- }
-
- BOOL CSplitterWnd::OnNcCreate(LPCREATESTRUCT lpcs)
- {
- if (!CWnd::OnNcCreate(lpcs))
- return FALSE;
-
- // remove WS_EX_CLIENTEDGE style from parent window
- // (the splitter itself will provide the 3d look)
- CWnd* pParent = GetParent();
- ASSERT_VALID(pParent);
- pParent->ModifyStyleEx(WS_EX_CLIENTEDGE, 0, SWP_DRAWFRAME);
-
- return TRUE;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CSplitterWnd default creation of parts
-
- // You must create ALL panes unless DYNAMIC_SPLIT is defined!
- // Usually the splitter window is invisible when creating a pane
- BOOL CSplitterWnd::CreateView(int row, int col,
- CRuntimeClass* pViewClass, SIZE sizeInit, CCreateContext* pContext)
- {
- #ifdef _DEBUG
- ASSERT_VALID(this);
- ASSERT(row >= 0 && row < m_nRows);
- ASSERT(col >= 0 && col < m_nCols);
- ASSERT(pViewClass != NULL);
- ASSERT(pViewClass->IsDerivedFrom(RUNTIME_CLASS(CWnd)));
- ASSERT(AfxIsValidAddress(pViewClass, sizeof(CRuntimeClass), FALSE));
-
- if (GetDlgItem(IdFromRowCol(row, col)) != NULL)
- {
- TRACE2("Error: CreateView - pane already exists for row %d, col %d.\n",
- row, col);
- ASSERT(FALSE);
- return FALSE;
- }
- #endif
-
- // set the initial size for that pane
- m_pColInfo[col].nIdealSize = sizeInit.cx;
- m_pRowInfo[row].nIdealSize = sizeInit.cy;
-
- BOOL bSendInitialUpdate = FALSE;
-
- CCreateContext contextT;
- if (pContext == NULL)
- {
- // if no context specified, generate one from the currently selected
- // client if possible
- CView* pOldView = (CView*)GetActivePane();
- if (pOldView != NULL && pOldView->IsKindOf(RUNTIME_CLASS(CView)))
- {
- // set info about last pane
- ASSERT(contextT.m_pCurrentFrame == NULL);
- contextT.m_pLastView = pOldView;
- contextT.m_pCurrentDoc = pOldView->GetDocument();
- if (contextT.m_pCurrentDoc != NULL)
- contextT.m_pNewDocTemplate =
- contextT.m_pCurrentDoc->GetDocTemplate();
- }
- pContext = &contextT;
- bSendInitialUpdate = TRUE;
- }
-
- CWnd* pWnd;
- TRY
- {
- pWnd = (CWnd*)pViewClass->CreateObject();
- if (pWnd == NULL)
- AfxThrowMemoryException();
- }
- CATCH_ALL(e)
- {
- TRACE0("Out of memory creating a splitter pane.\n");
- // Note: DELETE_EXCEPTION(e) not required
- return FALSE;
- }
- END_CATCH_ALL
-
- ASSERT_KINDOF(CWnd, pWnd);
- ASSERT(pWnd->m_hWnd == NULL); // not yet created
-
- DWORD dwStyle = AFX_WS_DEFAULT_VIEW;
- if (afxData.bWin4)
- dwStyle &= ~WS_BORDER;
-
- // Create with the right size (wrong position)
- CRect rect(CPoint(0,0), sizeInit);
- if (!pWnd->Create(NULL, NULL, dwStyle,
- rect, this, IdFromRowCol(row, col), pContext))
- {
- TRACE0("Warning: couldn't create client pane for splitter.\n");
- // pWnd will be cleaned up by PostNcDestroy
- return FALSE;
- }
- ASSERT((int)_AfxGetDlgCtrlID(pWnd->m_hWnd) == IdFromRowCol(row, col));
-
- // send initial notification message
- if (bSendInitialUpdate)
- pWnd->SendMessage(WM_INITIALUPDATE);
-
- return TRUE;
- }
-
- BOOL CSplitterWnd::CreateScrollBarCtrl(DWORD dwStyle, UINT nID)
- {
- ASSERT_VALID(this);
- ASSERT(m_hWnd != NULL);
-
- HWND hWnd = ::CreateWindow(_T("SCROLLBAR"), NULL,
- dwStyle | WS_VISIBLE | WS_CHILD,
- 0, 0, 1, 1, m_hWnd, (HMENU)nID,
- AfxGetInstanceHandle(), NULL);
-
- #ifdef _DEBUG
- if (hWnd == NULL)
- TRACE1("Warning: Window creation failed: GetLastError returns 0x%8.8X\n",
- GetLastError());
- #endif
-
- return hWnd != NULL;
- }
-
- int CSplitterWnd::IdFromRowCol(int row, int col) const
- {
- ASSERT_VALID(this);
- ASSERT(row >= 0);
- ASSERT(row < m_nRows);
- ASSERT(col >= 0);
- ASSERT(col < m_nCols);
-
- return AFX_IDW_PANE_FIRST + row * 16 + col;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CSplitterWnd attributes
-
- CWnd* CSplitterWnd::GetPane(int row, int col) const
- {
- ASSERT_VALID(this);
-
- CWnd* pView = GetDlgItem(IdFromRowCol(row, col));
- ASSERT(pView != NULL); // panes can be a CWnd, but are usually CViews
- return pView;
- }
-
- BOOL CSplitterWnd::IsChildPane(CWnd* pWnd, int* pRow, int* pCol)
- {
- ASSERT_VALID(this);
- ASSERT_VALID(pWnd);
-
- UINT nID = _AfxGetDlgCtrlID(pWnd->m_hWnd);
- if (IsChild(pWnd) && nID >= AFX_IDW_PANE_FIRST && nID <= AFX_IDW_PANE_LAST)
- {
- if (pRow != NULL)
- *pRow = (nID - AFX_IDW_PANE_FIRST) / 16;
- if (pCol != NULL)
- *pCol = (nID - AFX_IDW_PANE_FIRST) % 16;
- ASSERT(pRow == NULL || *pRow < m_nRows);
- ASSERT(pCol == NULL || *pCol < m_nCols);
- return TRUE;
- }
- else
- {
- if (pRow != NULL)
- *pRow = -1;
- if (pCol != NULL)
- *pCol = -1;
- return FALSE;
- }
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CSplitterWnd information access
-
- // The get routines return the current size
- // The set routines set the ideal size
- // RecalcLayout must be called to update current size
-
- void CSplitterWnd::GetRowInfo(int row, int& cyCur, int& cyMin) const
- {
- ASSERT_VALID(this);
- ASSERT(row >= 0 && row < m_nMaxRows);
-
- cyCur = m_pRowInfo[row].nCurSize;
- cyMin = m_pRowInfo[row].nMinSize;
- }
-
- void CSplitterWnd::SetRowInfo(int row, int cyIdeal, int cyMin)
- {
- ASSERT_VALID(this);
- ASSERT(row >= 0 && row < m_nMaxRows);
- ASSERT(cyIdeal >= 0);
- ASSERT(cyMin >= 0);
-
- m_pRowInfo[row].nIdealSize = cyIdeal;
- m_pRowInfo[row].nMinSize = cyMin;
- }
-
- void CSplitterWnd::GetColumnInfo(int col, int& cxCur, int& cxMin) const
- {
- ASSERT_VALID(this);
- ASSERT(col >= 0 && col < m_nMaxCols);
-
- cxCur = m_pColInfo[col].nCurSize;
- cxMin = m_pColInfo[col].nMinSize;
- }
-
- void CSplitterWnd::SetColumnInfo(int col, int cxIdeal, int cxMin)
- {
- ASSERT_VALID(this);
- ASSERT(col >= 0 && col < m_nMaxCols);
- ASSERT(cxIdeal >= 0);
- ASSERT(cxMin >= 0);
-
- m_pColInfo[col].nIdealSize = cxIdeal;
- m_pColInfo[col].nMinSize = cxMin;
- }
-
- DWORD CSplitterWnd::GetScrollStyle() const
- {
- DWORD dwStyle = 0;
- if (m_bHasHScroll)
- dwStyle |= WS_HSCROLL;
- if (m_bHasVScroll)
- dwStyle |= WS_VSCROLL;
- return dwStyle;
- }
-
- void CSplitterWnd::SetScrollStyle(DWORD dwStyle)
- {
- // optimize for scroll info already set correctly
- dwStyle &= (WS_HSCROLL|WS_VSCROLL);
- if (GetScrollStyle() == dwStyle)
- return;
-
- // update to new state
- m_bHasHScroll = (dwStyle & WS_HSCROLL) != 0;
- m_bHasVScroll = (dwStyle & WS_VSCROLL) != 0;
-
- CWnd* pScrollBar;
-
- // show/hide all the shared horz scroll bars
- for (int col = 0; col < m_nCols; col++)
- {
- pScrollBar = GetDlgItem(AFX_IDW_HSCROLL_FIRST + col);
- if (pScrollBar == NULL)
- {
- // create the scroll bar when necessary
- if (!CreateScrollBarCtrl(SBS_HORZ, AFX_IDW_HSCROLL_FIRST + col))
- AfxThrowResourceException();
- pScrollBar = GetDlgItem(AFX_IDW_HSCROLL_FIRST + col);
- }
- pScrollBar->ShowWindow(m_bHasHScroll ? SW_SHOW : SW_HIDE);
- }
-
- // show/hide all the shared vert scroll bars
- for (int row = 0; row < m_nRows; row++)
- {
- pScrollBar = GetDlgItem(AFX_IDW_VSCROLL_FIRST + row);
- if (pScrollBar == NULL)
- {
- // create the scroll bar when necessary
- if (!CreateScrollBarCtrl(SBS_VERT, AFX_IDW_VSCROLL_FIRST + row))
- AfxThrowResourceException();
- pScrollBar = GetDlgItem(AFX_IDW_VSCROLL_FIRST + row);
- }
- pScrollBar->ShowWindow(m_bHasVScroll ? SW_SHOW : SW_HIDE);
- }
-
- // show/destroy size box if necessary
- if (m_bHasVScroll && m_bHasHScroll)
- {
- pScrollBar = GetDlgItem(AFX_IDW_SIZE_BOX);
- if (pScrollBar == NULL)
- {
- // create size box when necessary
- if (!CreateScrollBarCtrl(SBS_SIZEBOX|WS_DISABLED, AFX_IDW_SIZE_BOX))
- AfxThrowResourceException();
- pScrollBar = GetDlgItem(AFX_IDW_SIZE_BOX);
- }
- pScrollBar->ShowWindow(SW_SHOW);
- }
- else
- {
- // the size box can be destroyed instead of hidden
- pScrollBar = GetDlgItem(AFX_IDW_SIZE_BOX);
- if (pScrollBar != NULL)
- pScrollBar->DestroyWindow();
- }
-
- // Note: call RecalcLayout for the new layout to take effect
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CSplitterWnd client operations/overridables
-
- void CSplitterWnd::DeleteView(int row, int col)
- {
- ASSERT_VALID(this);
-
- // if active child is being deleted - activate next
- CWnd* pPane = GetPane(row, col);
- ASSERT_KINDOF(CView, pPane);
- if (GetActivePane() == pPane)
- ActivateNext(FALSE);
-
- // default implementation assumes view will auto delete in PostNcDestroy
- pPane->DestroyWindow();
- }
-
- void CSplitterWnd::OnDrawSplitter(CDC* pDC, ESplitType nType,
- const CRect& rectArg)
- {
- // if pDC == NULL, then just invalidate
- if (pDC == NULL)
- {
- RedrawWindow(rectArg, NULL, RDW_INVALIDATE|RDW_NOCHILDREN);
- return;
- }
- ASSERT_VALID(pDC);
-
- // otherwise, actually draw
- CRect rect = rectArg;
- switch (nType)
- {
- case splitBorder:
- ASSERT(afxData.bWin4);
- pDC->Draw3dRect(rect, afxData.clrBtnShadow, afxData.clrBtnHilite);
- rect.InflateRect(-CX_BORDER, -CY_BORDER);
- pDC->Draw3dRect(rect, afxData.clrWindowFrame, afxData.clrBtnFace);
- return;
-
- case splitIntersection:
- ASSERT(!afxData.bWin4);
- break;
-
- case splitBox:
- if (afxData.bWin4)
- {
- pDC->Draw3dRect(rect, afxData.clrBtnFace, afxData.clrWindowFrame);
- rect.InflateRect(-CX_BORDER, -CY_BORDER);
- pDC->Draw3dRect(rect, afxData.clrBtnHilite, afxData.clrBtnShadow);
- rect.InflateRect(-CX_BORDER, -CY_BORDER);
- break;
- }
- // fall through...
- case splitBar:
- if (!afxData.bWin4)
- {
- pDC->Draw3dRect(rect, afxData.clrBtnHilite, afxData.clrBtnShadow);
- rect.InflateRect(-CX_BORDER, -CY_BORDER);
- }
- break;
-
- default:
- ASSERT(FALSE); // unknown splitter type
- }
-
- // fill the middle
- COLORREF clr = afxData.clrBtnFace;
- pDC->FillSolidRect(rect, clr);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // Dynamic row/col split etc
-
- AFX_STATIC int AFXAPI _AfxCanSplitRowCol(CSplitterWnd::CRowColInfo* pInfoBefore,
- int nBeforeSize, int nSizeSplitter)
- // request to split Before row at point nBeforeSize
- // returns size of new pane (nBeforeSize will be new size of Before pane)
- // return -1 if not big enough
- {
- ASSERT(pInfoBefore->nCurSize > 0);
- ASSERT(pInfoBefore->nMinSize > 0);
- ASSERT(nBeforeSize <= pInfoBefore->nCurSize);
-
- // space gets take from before pane (weird UI for > 2 splits)
- if (nBeforeSize < pInfoBefore->nMinSize)
- {
- TRACE0("Warning: split too small to fit in a new pane.\n");
- return -1;
- }
-
- int nNewSize = pInfoBefore->nCurSize - nBeforeSize - nSizeSplitter;
- if (nBeforeSize < pInfoBefore->nMinSize)
- {
- TRACE0("Warning: split too small to shrink old pane.\n");
- return -1;
- }
- if (nNewSize < (pInfoBefore+1)->nMinSize)
- {
- TRACE0("Warning: split too small to create new pane.\n");
- return -1;
- }
- return nNewSize;
- }
-
- BOOL CSplitterWnd::SplitRow(int cyBefore)
- {
- ASSERT_VALID(this);
- ASSERT(GetStyle() & SPLS_DYNAMIC_SPLIT);
- ASSERT(m_pDynamicViewClass != NULL);
- ASSERT(m_nRows < m_nMaxRows);
-
- cyBefore -= m_cyBorder;
- int rowNew = m_nRows;
- int cyNew = _AfxCanSplitRowCol(&m_pRowInfo[rowNew-1], cyBefore, m_cySplitter);
- if (cyNew == -1)
- return FALSE; // too small to split
-
- // create the scroll bar first (so new views can see that it is there)
- if (m_bHasVScroll &&
- !CreateScrollBarCtrl(SBS_VERT, AFX_IDW_VSCROLL_FIRST + rowNew))
- {
- TRACE0("Warning: SplitRow failed to create scroll bar.\n");
- return FALSE;
- }
-
- m_nRows++; // bump count during view creation
-
- // create new views to fill the new row (RecalcLayout will position)
- for (int col = 0; col < m_nCols; col++)
- {
- CSize size(m_pColInfo[col].nCurSize, cyNew);
- if (!CreateView(rowNew, col, m_pDynamicViewClass, size, NULL))
- {
- TRACE0("Warning: SplitRow failed to create new row.\n");
- // delete anything we partially created 'col' = # columns created
- while (col > 0)
- DeleteView(rowNew, --col);
- if (m_bHasVScroll)
- GetDlgItem(AFX_IDW_VSCROLL_FIRST + rowNew)->DestroyWindow();
- m_nRows--; // it didn't work out
- return FALSE;
- }
- }
-
- // new parts created - resize and re-layout
- m_pRowInfo[rowNew-1].nIdealSize = cyBefore;
- m_pRowInfo[rowNew].nIdealSize = cyNew;
- ASSERT(m_nRows == rowNew+1);
- RecalcLayout();
-
- return TRUE;
- }
-
- BOOL CSplitterWnd::SplitColumn(int cxBefore)
- {
- ASSERT_VALID(this);
- ASSERT(GetStyle() & SPLS_DYNAMIC_SPLIT);
- ASSERT(m_pDynamicViewClass != NULL);
- ASSERT(m_nCols < m_nMaxCols);
-
- cxBefore -= m_cxBorder;
- int colNew = m_nCols;
- int cxNew = _AfxCanSplitRowCol(&m_pColInfo[colNew-1], cxBefore, m_cxSplitter);
- if (cxNew == -1)
- return FALSE; // too small to split
-
- // create the scroll bar first (so new views can see that it is there)
- if (m_bHasHScroll &&
- !CreateScrollBarCtrl(SBS_HORZ, AFX_IDW_HSCROLL_FIRST + colNew))
- {
- TRACE0("Warning: SplitRow failed to create scroll bar.\n");
- return FALSE;
- }
-
- m_nCols++; // bump count during view creation
-
- // create new views to fill the new column (RecalcLayout will position)
- for (int row = 0; row < m_nRows; row++)
- {
- CSize size(cxNew, m_pRowInfo[row].nCurSize);
- if (!CreateView(row, colNew, m_pDynamicViewClass, size, NULL))
- {
- TRACE0("Warning: SplitColumn failed to create new column.\n");
- // delete anything we partially created 'col' = # columns created
- while (row > 0)
- DeleteView(--row, colNew);
- if (m_bHasHScroll)
- GetDlgItem(AFX_IDW_HSCROLL_FIRST + colNew)->DestroyWindow();
- m_nCols--; // it didn't work out
- return FALSE;
- }
- }
-
- // new parts created - resize and re-layout
- m_pColInfo[colNew-1].nIdealSize = cxBefore;
- m_pColInfo[colNew].nIdealSize = cxNew;
- ASSERT(m_nCols == colNew+1);
- RecalcLayout();
-
- return TRUE;
- }
-
- void CSplitterWnd::DeleteRow(int rowDelete)
- {
- ASSERT_VALID(this);
- ASSERT(GetStyle() & SPLS_DYNAMIC_SPLIT);
-
- ASSERT(m_nRows > 1);
- ASSERT(rowDelete < m_nRows);
-
- int rowActive, colActive;
- if (GetActivePane(&rowActive, &colActive) != NULL && rowActive == rowDelete)
- {
- if (++rowActive >= m_nRows)
- rowActive = 0;
- SetActivePane(rowActive, colActive);
- }
-
- CWnd* pScrollDel = m_bHasVScroll ?
- GetDlgItem(AFX_IDW_VSCROLL_FIRST+rowDelete) : NULL;
- for (int col = 0; col < m_nCols; col++)
- {
- DeleteView(rowDelete, col);
- for (int row = rowDelete+1; row < m_nRows; row++)
- {
- CWnd* pPane = GetPane(row, col);
- ASSERT(pPane != NULL);
- pPane->SetDlgCtrlID(IdFromRowCol(row-1, col));
- if (m_bHasVScroll && col == m_nCols-1)
- {
- CWnd* pScroll = GetDlgItem(AFX_IDW_VSCROLL_FIRST+row);
- if (pScroll != NULL)
- pScroll->SetDlgCtrlID(AFX_IDW_VSCROLL_FIRST+row-1);
- }
- }
- }
- m_nRows--;
- if (pScrollDel != NULL)
- pScrollDel->DestroyWindow();
-
- RecalcLayout(); // re-assign the space
- }
-
- void CSplitterWnd::DeleteColumn(int colDelete)
- {
- ASSERT_VALID(this);
- ASSERT(GetStyle() & SPLS_DYNAMIC_SPLIT);
-
- ASSERT(m_nCols > 1);
- ASSERT(colDelete < m_nCols);
-
- int rowActive, colActive;
- if (GetActivePane(&rowActive, &colActive) != NULL && colActive == colDelete)
- {
- if (++colActive >= m_nCols)
- colActive = 0;
- SetActivePane(rowActive, colActive);
- }
-
- CWnd* pScrollDel = m_bHasHScroll ?
- GetDlgItem(AFX_IDW_HSCROLL_FIRST+colDelete) : NULL;
- for (int row = 0; row < m_nRows; row++)
- {
- DeleteView(row, colDelete);
- for (int col = colDelete+1; col < m_nCols; col++)
- {
- CWnd* pPane = GetPane(row, col);
- ASSERT(pPane != NULL);
- pPane->SetDlgCtrlID(IdFromRowCol(row, col-1));
- if (m_bHasHScroll && row == m_nRows-1)
- {
- CWnd* pScroll = GetDlgItem(AFX_IDW_HSCROLL_FIRST+col);
- if (pScroll != NULL)
- pScroll->SetDlgCtrlID(AFX_IDW_HSCROLL_FIRST+col-1);
- }
- }
- }
- m_nCols--;
- if (pScrollDel != NULL)
- pScrollDel->DestroyWindow();
-
- RecalcLayout(); // re-assign the space
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CSplitterWnd tracking support
-
- // like GetClientRect but inset by shared scrollbars
- void CSplitterWnd::GetInsideRect(CRect& rect) const
- {
- ASSERT_VALID(this);
-
- GetClientRect(rect);
- ASSERT(rect.left == 0 && rect.top == 0);
-
- // subtract space for 3d borders
- rect.InflateRect(-m_cxBorder, -m_cyBorder);
-
- // subtract scrollbar clearance
- if (m_bHasVScroll)
- rect.right -= afxData.cxVScroll - CX_BORDER;
- if (m_bHasHScroll)
- rect.bottom -= afxData.cyHScroll - CY_BORDER;
- }
-
- void CSplitterWnd::StartTracking(int ht)
- {
- 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);
- }
-
- // allow active view to preserve focus before taking it away
- CView* pView = (CView*)GetActivePane();
- if (pView != NULL && pView->IsKindOf(RUNTIME_CLASS(CView)))
- {
- ASSERT_VALID(pView);
- CFrameWnd* pFrameWnd = GetParentFrame();
- ASSERT_VALID(pFrameWnd);
- pView->OnActivateFrame(WA_INACTIVE, pFrameWnd);
- }
-
- // steal focus and capture
- SetCapture();
- SetFocus();
-
- // make sure no updates are pending
- RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_UPDATENOW);
-
- // set tracking state and appropriate cursor
- m_bTracking = TRUE;
- OnInvertTracker(m_rectTracker);
- if (m_bTracking2)
- OnInvertTracker(m_rectTracker2);
- m_htTrack = ht;
- SetSplitCursor(ht);
- }
-
- void CSplitterWnd::TrackRowSize(int y, int row)
- {
- ASSERT_VALID(this);
- ASSERT(m_nRows > 1);
-
- CPoint pt(0, y);
- ClientToScreen(&pt);
- GetPane(row, 0)->ScreenToClient(&pt);
- m_pRowInfo[row].nIdealSize = pt.y; // new size
- if (pt.y < m_pRowInfo[row].nMinSize)
- {
- // resized too small
- m_pRowInfo[row].nIdealSize = 0; // make it go away
- if (GetStyle() & SPLS_DYNAMIC_SPLIT)
- DeleteRow(row);
- }
- else if (m_pRowInfo[row].nCurSize + m_pRowInfo[row+1].nCurSize
- < pt.y + m_pRowInfo[row+1].nMinSize)
- {
- // not enough room for other pane
- if (GetStyle() & SPLS_DYNAMIC_SPLIT)
- DeleteRow(row + 1);
- }
- }
-
- void CSplitterWnd::TrackColumnSize(int x, int col)
- {
- ASSERT_VALID(this);
- ASSERT(m_nCols > 1);
-
- CPoint pt(x, 0);
- ClientToScreen(&pt);
- GetPane(0, col)->ScreenToClient(&pt);
- m_pColInfo[col].nIdealSize = pt.x; // new size
- if (pt.x < m_pColInfo[col].nMinSize)
- {
- // resized too small
- m_pColInfo[col].nIdealSize = 0; // make it go away
- if (GetStyle() & SPLS_DYNAMIC_SPLIT)
- DeleteColumn(col);
- }
- else if (m_pColInfo[col].nCurSize + m_pColInfo[col+1].nCurSize
- < pt.x + m_pColInfo[col+1].nMinSize)
- {
- // not enough room for other pane
- if (GetStyle() & SPLS_DYNAMIC_SPLIT)
- DeleteColumn(col + 1);
- }
- }
-
- void CSplitterWnd::StopTracking(BOOL bAccept)
- {
- 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
- pOldActiveView->SetFocus(); // make sure focus is restored
- }
- }
- }
-
- void CSplitterWnd::GetHitRect(int ht, CRect& rectHit)
- {
- ASSERT_VALID(this);
-
- CRect rectClient;
- GetClientRect(&rectClient);
- rectClient.InflateRect(-m_cxBorder, -m_cyBorder);
- int cx = rectClient.Width();
- int cy = rectClient.Height();
- int x = rectClient.top;
- int y = rectClient.left;
-
- // hit rectangle does not include border
- // m_rectLimit will be limited to valid tracking rect
- // m_ptTrackOffset will be set to appropriate tracking offset
- m_ptTrackOffset.x = 0;
- m_ptTrackOffset.y = 0;
-
- if (ht == vSplitterBox)
- {
- cy = m_cySplitter - (2*m_cyBorder - afxData.bWin4);
- m_ptTrackOffset.y = -(cy / 2);
- ASSERT(m_pRowInfo[0].nCurSize > 0);
- m_rectLimit.bottom -= cy;
- }
- else if (ht == hSplitterBox)
- {
- cx = m_cxSplitter - (2*m_cxBorder - afxData.bWin4);
- m_ptTrackOffset.x = -(cx / 2);
- ASSERT(m_pColInfo[0].nCurSize > 0);
- m_rectLimit.right -= cx;
- }
- else if (ht >= vSplitterBar1 && ht <= vSplitterBar15)
- {
- cy = m_cySplitter - (2*m_cyBorder - afxData.bWin4);
- m_ptTrackOffset.y = -(cy / 2);
- for (int row = 0; row < ht - vSplitterBar1; row++)
- y += m_pRowInfo[row].nCurSize + m_cySplitterGap;
- m_rectLimit.top = y;
- y += m_pRowInfo[row].nCurSize + m_cyBorderShare + afxData.bWin4;
- m_rectLimit.bottom -= cy;
- }
- else if (ht >= hSplitterBar1 && ht <= hSplitterBar15)
- {
- cx = m_cxSplitter - (2*m_cxBorder - afxData.bWin4);
- m_ptTrackOffset.x = -(cx / 2);
- for (int col = 0; col < ht - hSplitterBar1; col++)
- x += m_pColInfo[col].nCurSize + m_cxSplitterGap;
- m_rectLimit.left = x;
- x += m_pColInfo[col].nCurSize + m_cxBorderShare + afxData.bWin4;
- m_rectLimit.right -= cx;
- }
- else
- {
- TRACE1("Error: GetHitRect(%d): Not Found!\n", ht);
- ASSERT(FALSE);
- }
-
- rectHit.right = (rectHit.left = x) + cx;
- rectHit.bottom = (rectHit.top = y) + cy;
- }
-
- int CSplitterWnd::HitTest(CPoint pt) const
- {
- ASSERT_VALID(this);
-
- CRect rectClient;
- GetClientRect(&rectClient);
- rectClient.InflateRect(-m_cxBorder, -m_cyBorder);
-
- CRect rectInside;
- GetInsideRect(rectInside);
-
- if (m_bHasVScroll && m_nRows < m_nMaxRows &&
- CRect(rectInside.right, rectClient.top, rectClient.right,
- rectClient.top + m_cySplitter - afxData.bWin4).PtInRect(pt))
- {
- return vSplitterBox;
- }
-
- if (m_bHasHScroll && m_nCols < m_nMaxCols &&
- CRect(rectClient.left, rectInside.bottom,
- rectClient.left + m_cxSplitter - afxData.bWin4,
- rectClient.bottom).PtInRect(pt))
- {
- return hSplitterBox;
- }
-
- // for hit detect, include the border of splitters
- CRect rect;
- rect = rectClient;
- for (int col = 0; col < m_nCols - 1; col++)
- {
- rect.left += m_pColInfo[col].nCurSize;
- rect.right = rect.left + m_cxSplitterGap;
- if (rect.PtInRect(pt))
- break;
- rect.left = rect.right;
- }
-
- rect = rectClient;
- for (int row = 0; row < m_nRows - 1; row++)
- {
- rect.top += m_pRowInfo[row].nCurSize;
- rect.bottom = rect.top + m_cySplitterGap;
- if (rect.PtInRect(pt))
- break;
- rect.top = rect.bottom;
- }
-
- // row and col set for hit splitter (if not hit will be past end)
- if (col != m_nCols - 1)
- {
- if (row != m_nRows - 1)
- return splitterIntersection1 + row * 15 + col;
- return hSplitterBar1 + col;
- }
-
- if (row != m_nRows - 1)
- return vSplitterBar1 + row;
-
- return noHit;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CSplitterWnd tracking visuals
-
- void CSplitterWnd::OnInvertTracker(const CRect& rect)
- {
- ASSERT_VALID(this);
- ASSERT(!rect.IsRectEmpty());
- ASSERT((GetStyle() & WS_CLIPCHILDREN) == 0);
-
- // pat-blt without clip children on
- CDC* pDC = GetDC();
- // invert the brush pattern (looks just like frame window sizing)
- CBrush* pBrush = CDC::GetHalftoneBrush();
- HBRUSH hOldBrush = NULL;
- if (pBrush != NULL)
- hOldBrush = (HBRUSH)SelectObject(pDC->m_hDC, pBrush->m_hObject);
- pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATINVERT);
- if (hOldBrush != NULL)
- SelectObject(pDC->m_hDC, hOldBrush);
- ReleaseDC(pDC);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CSplitterWnd commands
-
- // Keyboard interface
- BOOL CSplitterWnd::DoKeyboardSplit()
- {
- ASSERT_VALID(this);
-
- int ht;
- if (m_nRows > 1 && m_nCols > 1)
- ht = splitterIntersection1; // split existing row+col
- else if (m_nRows > 1)
- ht = vSplitterBar1; // split existing row
- else if (m_nCols > 1)
- ht = hSplitterBar1; // split existing col
- else if (m_nMaxRows > 1 && m_nMaxCols > 1)
- ht = bothSplitterBox; // we can split both
- else if (m_nMaxRows > 1)
- ht = vSplitterBox; // we can split rows
- else if (m_nMaxCols > 1)
- ht = hSplitterBox; // we can split columns
- else
- return FALSE; // can't split
-
- // start tracking
- StartTracking(ht);
-
- CRect rect;
- rect.left = m_rectTracker.Width() / 2;
- rect.top = m_rectTracker.Height() / 2;
- if (m_ptTrackOffset.y != 0)
- rect.top = m_rectTracker.top;
- if (m_ptTrackOffset.x != 0)
- rect.left = m_bTracking2 ? m_rectTracker2.left :m_rectTracker.left;
- rect.OffsetRect(-m_ptTrackOffset.x, -m_ptTrackOffset.y);
- ClientToScreen(&rect);
- SetCursorPos(rect.left, rect.top);
-
- return TRUE;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // Main drawing and layout
-
- void CSplitterWnd::OnDisplayChange()
- {
- if (!IsIconic() && IsWindowVisible())
- RecalcLayout();
- }
-
- void CSplitterWnd::OnSize(UINT nType, int cx, int cy)
- {
- if (nType != SIZE_MINIMIZED && cx > 0 && cy > 0)
- RecalcLayout();
-
- CWnd::OnSize(nType, cx, cy);
- }
-
- // Generic routine:
- // for X direction: pInfo = m_pColInfo, nMax = m_nMaxCols, nSize = cx
- // for Y direction: pInfo = m_pRowInfo, nMax = m_nMaxRows, nSize = cy
- AFX_STATIC void AFXAPI _AfxLayoutRowCol(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
- ASSERT(afxData.cxBorder2 == afxData.cyBorder2);
- (pInfo-1)->nCurSize += nSize + afxData.cxBorder2;
- 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(afxData.cxBorder2 == afxData.cyBorder2);
- pInfo->nCurSize += nSize;
- if (pInfo->nCurSize > (nSizeSplitter - afxData.cxBorder2))
- pInfo->nCurSize -= (nSizeSplitter - afxData.cyBorder2);
- 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)
- AFX_STATIC void AFXAPI _AfxDeferClientPos(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 <= 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)
- if (!afxData.bWin4)
- {
- if (bScrollBar)
- rect.InflateRect(CX_BORDER, CY_BORDER);
- else
- pWnd->CalcWindowRect(&rect);
- }
-
- // adjust for 3d border (splitter windows have implied border)
- if ((pWnd->GetExStyle() & WS_EX_CLIENTEDGE) ||
- pWnd->IsKindOf(RUNTIME_CLASS(CSplitterWnd)))
- 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);
- }
-
- CWnd* CSplitterWnd::GetSizingParent()
- {
- ASSERT_VALID(this);
-
- if (!afxData.bWin4)
- return NULL;
-
- // size box is in lower right corner of this window
- CRect rectClient;
- GetClientRect(rectClient);
-
- // find sizeable parent window
- CWnd* pParent = this;
- if (!(pParent->GetStyle() & WS_THICKFRAME))
- pParent = GetParent();
-
- // only allow if not maximized and has thick frame
- ASSERT_VALID(pParent);
- if ((pParent->GetStyle() & (WS_THICKFRAME|WS_MAXIMIZE)) == WS_THICKFRAME)
- {
- // convert client area of frame window relative to splitter
- CRect rect;
- pParent->GetClientRect(rect);
- pParent->ClientToScreen(rect);
- ScreenToClient(rect);
-
- // must match exactly to get the size box
- if (rectClient.BottomRight() == rect.BottomRight())
- return pParent;
- }
-
- return NULL; // no sizeable parent found
- }
-
- void CSplitterWnd::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)
- _AfxLayoutRowCol(m_pColInfo, m_nCols, rectInside.Width(), m_cxSplitterGap);
- _AfxLayoutRowCol(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) - afxData.bNotWin4;
- int cy = (rectClient.bottom - rectInside.bottom) - afxData.bNotWin4;
-
- // 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
- _AfxDeferClientPos(&layout, pScrollBar,
- rectInside.right + afxData.bNotWin4,
- rectInside.bottom + afxData.bNotWin4, cx, cy, TRUE);
- }
-
- // reposition scroll bars
- if (m_bHasHScroll)
- {
- int cxSplitterBox = m_cxSplitter + afxData.bNotWin4;// split box bigger
- int x = rectClient.left;
- int y = rectInside.bottom + afxData.bNotWin4;
- 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;
- _AfxDeferClientPos(&layout, pScrollBar, x, y, cx, cy, TRUE);
- x += cx + m_cxSplitterGap;
- }
- }
-
- if (m_bHasVScroll)
- {
- int cySplitterBox = m_cySplitter + afxData.bNotWin4;// split box bigger
- int x = rectInside.right + afxData.bNotWin4;
- 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;
- _AfxDeferClientPos(&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);
- _AfxDeferClientPos(&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 CSplitterWnd::DrawAllSplitBars(CDC* pDC, int cxInside, int cyInside)
- {
- ASSERT_VALID(this);
-
- // draw column split bars
- CRect rect;
- GetClientRect(rect);
- rect.left += m_cxBorder;
- for (int col = 0; col < m_nCols - 1; col++)
- {
- rect.left += m_pColInfo[col].nCurSize + m_cxBorderShare;
- rect.right = rect.left + m_cxSplitter;
- if (rect.left > cxInside)
- break; // stop if not fully visible
- OnDrawSplitter(pDC, splitBar, rect);
- rect.left = rect.right + m_cxBorderShare;
- }
-
- // draw row split bars
- GetClientRect(rect);
- rect.top += m_cyBorder;
- for (int row = 0; row < m_nRows - 1; row++)
- {
- rect.top += m_pRowInfo[row].nCurSize + m_cyBorderShare;
- rect.bottom = rect.top + m_cySplitter;
- if (rect.top > cyInside)
- break; // stop if not fully visible
- OnDrawSplitter(pDC, splitBar, rect);
- rect.top = rect.bottom + m_cyBorderShare;
- }
-
- // draw pane borders
- if (afxData.bWin4)
- {
- GetClientRect(rect);
- int x = rect.left;
- for (col = 0; col < m_nCols; col++)
- {
- int cx = m_pColInfo[col].nCurSize + 2*m_cxBorder;
- if (col == m_nCols-1 && m_bHasVScroll)
- cx += afxData.cxVScroll - CX_BORDER;
- int y = rect.top;
- for (int row = 0; row < m_nRows; row++)
- {
- int cy = m_pRowInfo[row].nCurSize + 2*m_cyBorder;
- if (row == m_nRows-1 && m_bHasHScroll)
- cy += afxData.cyHScroll - CX_BORDER;
- OnDrawSplitter(pDC, splitBorder, CRect(x, y, x+cx, y+cy));
- y += cy + m_cySplitterGap - 2*m_cyBorder;
- }
- x += cx + m_cxSplitterGap - 2*m_cxBorder;
- }
- }
- }
-
- void CSplitterWnd::OnPaint()
- {
- ASSERT_VALID(this);
- CPaintDC dc(this);
-
- CRect rectClient;
- GetClientRect(&rectClient);
- rectClient.InflateRect(-m_cxBorder, -m_cyBorder);
-
- CRect rectInside;
- GetInsideRect(rectInside);
-
- // draw the splitter boxes
- if (m_bHasVScroll && m_nRows < m_nMaxRows)
- {
- OnDrawSplitter(&dc, splitBox,
- CRect(rectInside.right + afxData.bNotWin4, rectClient.top,
- rectClient.right, rectClient.top + m_cySplitter));
- }
-
- if (m_bHasHScroll && m_nCols < m_nMaxCols)
- {
- OnDrawSplitter(&dc, splitBox,
- CRect(rectClient.left, rectInside.bottom + afxData.bNotWin4,
- rectClient.left + m_cxSplitter, rectClient.bottom));
- }
-
- // extend split bars to window border (past margins)
- DrawAllSplitBars(&dc, rectInside.right, rectInside.bottom);
-
- if (!afxData.bWin4)
- {
- // draw splitter intersections (inside only)
- GetInsideRect(rectInside);
- dc.IntersectClipRect(rectInside);
- CRect rect;
- rect.top = rectInside.top;
- for (int row = 0; row < m_nRows - 1; row++)
- {
- rect.top += m_pRowInfo[row].nCurSize + m_cyBorderShare;
- rect.bottom = rect.top + m_cySplitter;
- rect.left = rectInside.left;
- for (int col = 0; col < m_nCols - 1; col++)
- {
- rect.left += m_pColInfo[col].nCurSize + m_cxBorderShare;
- rect.right = rect.left + m_cxSplitter;
- OnDrawSplitter(&dc, splitIntersection, rect);
- rect.left = rect.right + m_cxBorderShare;
- }
- rect.top = rect.bottom + m_cxBorderShare;
- }
- }
- }
-
- BOOL CSplitterWnd::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
- {
- if (nHitTest == HTCLIENT && pWnd == this && !m_bTracking)
- return TRUE; // we will handle it in the mouse move
-
- return CWnd::OnSetCursor(pWnd, nHitTest, message);
- }
-
- // cache of last needed cursor
- AFX_STATIC_DATA HCURSOR _afx_hcurLast = NULL;
- AFX_STATIC_DATA HCURSOR _afx_hcurDestroy = NULL;
- AFX_STATIC_DATA UINT _afx_idcPrimaryLast = 0; // store the primary IDC
-
- void CSplitterWnd::SetSplitCursor(int ht)
- {
- UINT idcPrimary; // app supplied cursor
- LPCTSTR idcSecondary; // system supplied cursor (MAKEINTRESOURCE)
-
- AfxLockGlobals(CRIT_SPLITTERWND);
- if (ht == vSplitterBox ||
- ht >= vSplitterBar1 && ht <= vSplitterBar15)
- {
- idcPrimary = AFX_IDC_VSPLITBAR;
- idcSecondary = IDC_SIZENS;
- }
- else if (ht == hSplitterBox ||
- ht >= hSplitterBar1 && ht <= hSplitterBar15)
- {
- idcPrimary = AFX_IDC_HSPLITBAR;
- idcSecondary = IDC_SIZEWE;
- }
- else if (ht == bothSplitterBox ||
- (ht >= splitterIntersection1 && ht <= splitterIntersection225))
- {
- idcPrimary = AFX_IDC_SMALLARROWS;
- idcSecondary = IDC_SIZEALL;
- }
- else
- {
- SetCursor(afxData.hcurArrow);
- idcPrimary = 0; // don't use it
- idcSecondary = 0; // don't use it
- }
-
- if (idcPrimary != 0)
- {
- HCURSOR hcurToDestroy = NULL;
- if (idcPrimary != _afx_idcPrimaryLast)
- {
- HINSTANCE hInst = AfxFindResourceHandle(
- MAKEINTRESOURCE(idcPrimary), RT_GROUP_CURSOR);
-
- // load in another cursor
- hcurToDestroy = _afx_hcurDestroy;
-
- // Note: If this LoadCursor call fails, it is likely that
- // _AFX_NO_SPLITTER_RESOURCES is defined in your .RC file.
- // To correct the situation, remove the following line from your
- // resource script:
- // #define _AFX_NO_SPLITTER_RESOURCES
- // This should be done using the Resource.Set Includes... command.
-
- if ((_afx_hcurDestroy = _afx_hcurLast =
- ::LoadCursor(hInst, MAKEINTRESOURCE(idcPrimary))) == NULL)
- {
- // will not look as good
- TRACE0("Warning: Could not find splitter cursor - using system provided alternative.\n");
-
- ASSERT(_afx_hcurDestroy == NULL); // will not get destroyed
- _afx_hcurLast = ::LoadCursor(NULL, idcSecondary);
- ASSERT(_afx_hcurLast != NULL);
- }
- _afx_idcPrimaryLast = idcPrimary;
- }
- ASSERT(_afx_hcurLast != NULL);
- ::SetCursor(_afx_hcurLast);
- ASSERT(_afx_hcurLast != hcurToDestroy);
- if (hcurToDestroy != NULL)
- ::DestroyCursor(hcurToDestroy); // destroy after being set
- }
- AfxUnlockGlobals(CRIT_SPLITTERWND);
- }
-
- void CSplitterWnd::OnMouseMove(UINT /*nFlags*/, CPoint pt)
- {
- 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);
- }
- }
- }
- else
- {
- // simply hit-test and set appropriate cursor
-
- int ht = HitTest(pt);
- SetSplitCursor(ht);
- }
- }
-
- void CSplitterWnd::OnLButtonDown(UINT /*nFlags*/, CPoint pt)
- {
- if (m_bTracking)
- return;
-
- StartTracking(HitTest(pt));
- }
-
- void CSplitterWnd::OnLButtonDblClk(UINT /*nFlags*/, CPoint pt)
- {
- int ht = HitTest(pt);
- CRect rect;
-
- StopTracking(FALSE);
-
- if ((GetStyle() & SPLS_DYNAMIC_SPLIT) == 0)
- return; // do nothing if layout is static
-
- if (ht == vSplitterBox)
- {
- // half split
- SplitRow(m_pRowInfo[0].nCurSize / 2);
- }
- else if (ht == hSplitterBox)
- {
- // half split
- SplitColumn(m_pColInfo[0].nCurSize / 2);
- }
- else if (ht >= vSplitterBar1 && ht <= vSplitterBar15)
- {
- int rowDelete = ht - vSplitterBar1;
- // don't delete the active row
- int row;
- if (GetActivePane(&row, NULL) != NULL && rowDelete == row)
- ++rowDelete;
- DeleteRow(rowDelete);
- }
- else if (ht >= hSplitterBar1 && ht <= hSplitterBar15)
- {
- int colDelete = ht - hSplitterBar1;
- // don't delete the active column
- int col;
- if (GetActivePane(NULL, &col) != NULL && colDelete == col)
- ++colDelete;
- DeleteColumn(colDelete);
- }
- else if (ht >= splitterIntersection1 && ht <= splitterIntersection225)
- {
- int rowDelete = (ht - splitterIntersection1) / 15;
- int colDelete = (ht - splitterIntersection1) % 15;
- int row, col;
- if (GetActivePane(&row, &col) != NULL)
- {
- // don't delete the active row or column
- if (col == colDelete)
- ++colDelete;
- if (row == rowDelete)
- ++rowDelete;
- }
- DeleteRow(rowDelete);
- DeleteColumn(colDelete);
- }
- }
-
- void CSplitterWnd::OnLButtonUp(UINT /*nFlags*/, CPoint /*pt*/)
- {
- StopTracking(TRUE);
- }
-
- void CSplitterWnd::OnCancelMode()
- {
- StopTracking(FALSE);
- }
-
- void CSplitterWnd::OnKeyDown(UINT nChar, UINT /*nRepCnt*/, UINT /*nFlags*/)
- {
- CPoint pt;
- GetCursorPos(&pt);
-
- int cz = GetKeyState(VK_CONTROL) < 0 ? 1 : 16;
- int dx = 0;
- int dy = 0;
-
- switch (nChar)
- {
- case VK_ESCAPE:
- StopTracking(FALSE);
- return;
- case VK_RETURN:
- StopTracking(TRUE);
- return;
-
- case VK_LEFT:
- dx = -1;
- break;
- case VK_RIGHT:
- dx = +1;
- break;
- case VK_UP:
- dy = -1;
- break;
- case VK_DOWN:
- dy = +1;
- break;
-
- default:
- Default(); // pass other keys through
- return;
- }
-
- if (m_htTrack == vSplitterBox ||
- m_htTrack >= vSplitterBar1 && m_htTrack <= vSplitterBar15)
- {
- // no movement along X axis
- dx = 0;
- }
- if (m_htTrack == hSplitterBox ||
- m_htTrack >= hSplitterBar1 && m_htTrack <= hSplitterBar15)
- {
- // no movement along Y axis
- dy = 0;
- }
-
- // adjust to new position
- pt.x += dx * cz;
- pt.y += dy * cz;
-
- // make sure within valid limits
- ScreenToClient(&pt);
- 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;
- ClientToScreen(&pt);
-
- // cause WM_MOUSEMOVE to filter through
- SetCursorPos(pt.x, pt.y);
- }
-
- void CSplitterWnd::OnSysCommand(UINT nID, LPARAM lParam)
- {
- if ((nID & 0xFFF0) == SC_SIZE)
- {
- CWnd* pParent = GetSizingParent();
- if (pParent != NULL)
- {
- pParent->SendMessage(WM_SYSCOMMAND, (WPARAM)nID, lParam);
- return;
- }
- }
- CWnd::OnSysCommand(nID, lParam);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CSplitterWnd command routing
-
- BOOL CSplitterWnd::OnCommand(WPARAM wParam, LPARAM lParam)
- {
- if (CWnd::OnCommand(wParam, lParam))
- return TRUE;
-
- // route commands to the splitter to the parent frame window
- return GetParentFrame()->SendMessage(WM_COMMAND, wParam, lParam);
- }
-
- BOOL CSplitterWnd::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
- {
- if (CWnd::OnNotify(wParam, lParam, pResult))
- return TRUE;
-
- // route commands to the splitter to the parent frame window
- *pResult = GetParentFrame()->SendMessage(WM_NOTIFY, wParam, lParam);
- return TRUE;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // Scroll messages
-
- BOOL CSplitterWnd::OnMouseWheel(UINT fFlags, short zDelta, CPoint point)
- {
- BOOL bRetVal = FALSE;
- int row;
- int col;
-
- // find panes in the splitter that has scroll bars
- // and have them do their scrolling
-
- for (row = 0; row < m_nRows; row++)
- {
- for (col = 0; col < m_nCols; col++)
- {
- // only do the scrolling if the window is-a CScrollView
-
- CWnd* pPane = GetPane(row, col);
- CScrollView* pView = DYNAMIC_DOWNCAST(CScrollView, pPane);
- if (pView != NULL)
- {
- // prefer to scroll vertically if available
-
- CScrollBar* pBar = pView->GetScrollBarCtrl(SB_VERT);
- if (pBar == NULL)
- {
- pBar = pView->GetScrollBarCtrl(SB_HORZ);
- if (pBar == NULL)
- continue;
- }
-
- // get the old position, do the scrolling, and
- // then trigger the repaint
-
- int nOldPos = pBar->GetScrollPos();
- if (pView->DoMouseWheel(fFlags, zDelta, point))
- bRetVal = TRUE;
-
- if (col < m_nCols -1)
- pBar->SetScrollPos(nOldPos, FALSE);
- }
- }
- }
-
- return TRUE;
- }
-
- void CSplitterWnd::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
- {
- ASSERT(pScrollBar != NULL);
- int col = _AfxGetDlgCtrlID(pScrollBar->m_hWnd) - AFX_IDW_HSCROLL_FIRST;
- ASSERT(col >= 0 && col < m_nMaxCols);
-
- ASSERT(m_nRows > 0);
- int nOldPos = pScrollBar->GetScrollPos();
- #ifdef _DEBUG
- int nNewPos;
- #endif
- for (int row = 0; row < m_nRows; row++)
- {
- GetPane(row, col)->SendMessage(WM_HSCROLL,
- MAKELONG(nSBCode, nPos), (LPARAM)pScrollBar->m_hWnd);
- #ifdef _DEBUG
- if (row == 0)
- {
- nNewPos = pScrollBar->GetScrollPos();
- if (pScrollBar->GetScrollPos() != nNewPos)
- {
- TRACE0("Warning: scroll panes setting different scroll positions.\n");
- // stick with the last one set
- }
- }
- #endif //_DEBUG
- // set the scroll pos to the value it was originally for the next pane
- if (row < m_nRows - 1)
- pScrollBar->SetScrollPos(nOldPos, FALSE);
- }
- }
-
- void CSplitterWnd::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
- {
- ASSERT(pScrollBar != NULL);
- int row = _AfxGetDlgCtrlID(pScrollBar->m_hWnd) - AFX_IDW_VSCROLL_FIRST;
- ASSERT(row >= 0 && row < m_nMaxRows);
-
- ASSERT(m_nCols > 0);
- int nOldPos = pScrollBar->GetScrollPos();
- #ifdef _DEBUG
- int nNewPos;
- #endif
- for (int col = 0; col < m_nCols; col++)
- {
- GetPane(row, col)->SendMessage(WM_VSCROLL,
- MAKELONG(nSBCode, nPos), (LPARAM)pScrollBar->m_hWnd);
- #ifdef _DEBUG
- if (col == 0)
- {
- nNewPos = pScrollBar->GetScrollPos();
- if (pScrollBar->GetScrollPos() != nNewPos)
- {
- TRACE0("Warning: scroll panes setting different scroll positions.\n");
- // stick with the last one set
- }
- }
- #endif //_DEBUG
- // set the scroll pos to the value it was originally for the next pane
- if (col < m_nCols - 1)
- pScrollBar->SetScrollPos(nOldPos, FALSE);
- }
- }
-
- // synchronized scrolling
- BOOL CSplitterWnd::DoScroll(CView* pViewFrom, UINT nScrollCode, BOOL bDoScroll)
- {
- ASSERT_VALID(pViewFrom);
-
- int rowFrom, colFrom;
- if (!IsChildPane(pViewFrom, &rowFrom, &colFrom))
- return FALSE;
-
- BOOL bResult = FALSE;
-
- // save original positions
- int nOldVert = 0;
- CScrollBar* pScrollVert = pViewFrom->GetScrollBarCtrl(SB_VERT);
- if (pScrollVert != NULL)
- nOldVert = pScrollVert->GetScrollPos();
- int nOldHorz = 0;
- CScrollBar* pScrollHorz = pViewFrom->GetScrollBarCtrl(SB_HORZ);
- if (pScrollHorz != NULL)
- nOldHorz = pScrollHorz->GetScrollPos();
-
- // scroll the view from which the message is from
- if (pViewFrom->OnScroll(nScrollCode, 0, bDoScroll))
- bResult = TRUE;
-
- if (pScrollVert != NULL)
- {
- #ifdef _DEBUG
- int nNewVert = pScrollVert->GetScrollPos();
- #endif
- // scroll related columns
- for (int col = 0; col < m_nCols; col++)
- {
- if (col == colFrom)
- continue;
-
- // set the scroll pos to the value it was originally
- pScrollVert->SetScrollPos(nOldVert, FALSE);
-
- // scroll the pane
- CView* pView = (CView*)GetPane(rowFrom, col);
- ASSERT_KINDOF(CView, pView);
- ASSERT(pView != pViewFrom);
- if (pView->OnScroll(MAKEWORD(-1, HIBYTE(nScrollCode)), 0,
- bDoScroll))
- {
- bResult = TRUE;
- }
-
- #ifdef _DEBUG
- if (pScrollVert->GetScrollPos() != nNewVert)
- {
- TRACE0("Warning: scroll panes setting different scroll positions.\n");
- // stick with the last one set
- }
- #endif
- }
- }
-
- if (pScrollHorz != NULL)
- {
- #ifdef _DEBUG
- int nNewHorz = pScrollHorz->GetScrollPos();
- #endif
- // scroll related rows
- for (int row = 0; row < m_nRows; row++)
- {
- if (row == rowFrom)
- continue;
-
- // set the scroll pos to the value it was originally
- pScrollHorz->SetScrollPos(nOldHorz, FALSE);
-
- // scroll the pane
- CView* pView = (CView*)GetPane(row, colFrom);
- ASSERT_KINDOF(CView, pView);
- ASSERT(pView != pViewFrom);
- if (pView->OnScroll(MAKEWORD(LOBYTE(nScrollCode), -1), 0,
- bDoScroll))
- {
- bResult = TRUE;
- }
-
- #ifdef _DEBUG
- if (pScrollHorz->GetScrollPos() != nNewHorz)
- {
- TRACE0("Warning: scroll panes setting different scroll positions.\n");
- // stick with the last one set
- }
- #endif
- }
- }
-
- return bResult;
- }
-
- BOOL CSplitterWnd::DoScrollBy(CView* pViewFrom, CSize sizeScroll, BOOL bDoScroll)
- {
- int rowFrom, colFrom;
- if (!IsChildPane(pViewFrom, &rowFrom, &colFrom))
- return FALSE;
-
- BOOL bResult = FALSE;
-
- // save original positions
- int nOldVert = 0;
- CScrollBar* pScrollVert = pViewFrom->GetScrollBarCtrl(SB_VERT);
- if (pScrollVert != NULL)
- nOldVert = pScrollVert->GetScrollPos();
- int nOldHorz = 0;
- CScrollBar* pScrollHorz = pViewFrom->GetScrollBarCtrl(SB_HORZ);
- if (pScrollHorz != NULL)
- nOldHorz = pScrollHorz->GetScrollPos();
-
- // scroll the view from which the message is from
- if (pViewFrom->OnScrollBy(sizeScroll, bDoScroll))
- bResult = TRUE;
-
- if (pScrollVert != NULL)
- {
- #ifdef _DEBUG
- int nNewVert = pScrollVert->GetScrollPos();
- #endif
- // scroll related columns
- for (int col = 0; col < m_nCols; col++)
- {
- if (col == colFrom)
- continue;
-
- // set the scroll pos to the value it was originally for the next pane
- pScrollVert->SetScrollPos(nOldVert, FALSE);
-
- // scroll the pane
- CView* pView = (CView*)GetPane(rowFrom, col);
- ASSERT_KINDOF(CView, pView);
- ASSERT(pView != pViewFrom);
- if (pView->OnScrollBy(CSize(0, sizeScroll.cy), bDoScroll))
- bResult = TRUE;
-
- #ifdef _DEBUG
- if (pScrollVert->GetScrollPos() != nNewVert)
- {
- TRACE0("Warning: scroll panes setting different scroll positions.\n");
- // stick with the last one set
- }
- #endif
- }
- }
-
- if (pScrollHorz != NULL)
- {
- #ifdef _DEBUG
- int nNewHorz = pScrollHorz->GetScrollPos();
- #endif
- // scroll related rows
- for (int row = 0; row < m_nRows; row++)
- {
- if (row == rowFrom)
- continue;
-
- // set the scroll pos to the value it was originally for the next pane
- pScrollHorz->SetScrollPos(nOldHorz, FALSE);
-
- // scroll the pane
- CView* pView = (CView*)GetPane(row, colFrom);
- ASSERT_KINDOF(CView, pView);
- ASSERT(pView != pViewFrom);
- if (pView->OnScrollBy(CSize(sizeScroll.cx, 0), bDoScroll))
- bResult = TRUE;
-
- #ifdef _DEBUG
- if (pScrollHorz->GetScrollPos() != nNewHorz)
- {
- TRACE0("Warning: scroll panes setting different scroll positions.\n");
- // stick with the last one set
- }
- #endif
- }
- }
-
- return bResult;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // Focus control and control over the current pane/child
-
- BOOL CSplitterWnd::CanActivateNext(BOOL)
- {
- ASSERT_VALID(this);
-
- if (GetActivePane() == NULL)
- {
- TRACE0("Warning: Can't go to next pane - there is no current pane.\n");
- return FALSE;
- }
- ASSERT(m_nRows != 0);
- ASSERT(m_nCols != 0);
- // if more than 1x1 we can go to the next or prev pane
- return (m_nRows > 1) || (m_nCols > 1);
- }
-
- void CSplitterWnd::ActivateNext(BOOL bPrev)
- {
- ASSERT_VALID(this);
-
- // find the coordinate of the current pane
- int row, col;
- if (GetActivePane(&row, &col) == NULL)
- {
- TRACE0("Warning: Cannot go to next pane - there is no current view.\n");
- return;
- }
- ASSERT(row >= 0 && row < m_nRows);
- ASSERT(col >= 0 && col < m_nCols);
-
- // determine next pane
- if (bPrev)
- {
- // prev
- if (--col < 0)
- {
- col = m_nCols - 1;
- if (--row < 0)
- row = m_nRows - 1;
- }
- }
- else
- {
- // next
- if (++col >= m_nCols)
- {
- col = 0;
- if (++row >= m_nRows)
- row = 0;
- }
- }
-
- // set newly active pane
- SetActivePane(row, col);
- }
-
- void CSplitterWnd::SetActivePane(int row, int col, CWnd* pWnd)
- {
- // 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
- {
- TRACE0("Warning: Next pane is not a view - calling SetFocus.\n");
- pPane->SetFocus();
- }
- }
-
- CWnd* CSplitterWnd::GetActivePane(int* pRow, int* pCol)
- // return active view, NULL when no active view
- {
- ASSERT_VALID(this);
-
- // attempt to use active view of frame window
- CWnd* pView = NULL;
- CFrameWnd* pFrameWnd = GetParentFrame();
- ASSERT_VALID(pFrameWnd);
- pView = pFrameWnd->GetActiveView();
-
- // failing that, use the current focus
- if (pView == NULL)
- pView = GetFocus();
-
- // make sure the pane is a child pane of the splitter
- if (pView != NULL && !IsChildPane(pView, pRow, pCol))
- pView = NULL;
-
- return pView;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CSplitterWnd diagnostics
-
- #ifdef _DEBUG
- void CSplitterWnd::AssertValid() const
- {
- CWnd::AssertValid();
- ASSERT(m_nMaxRows >= 1);
- ASSERT(m_nMaxCols >= 1);
- ASSERT(m_nMaxCols > 1 || m_nMaxRows > 1); // 1x1 is not permitted
- ASSERT(m_nRows >= 1);
- ASSERT(m_nCols >= 1);
- ASSERT(m_nRows <= m_nMaxRows);
- ASSERT(m_nCols <= m_nMaxCols);
- }
-
- void CSplitterWnd::Dump(CDumpContext& dc) const
- {
- CWnd::Dump(dc);
-
- if (m_pDynamicViewClass != NULL)
- dc << "m_pDynamicViewClass = " << m_pDynamicViewClass->m_lpszClassName;
- dc << "\nm_nMaxRows = " << m_nMaxRows;
- dc << "\nm_nMaxCols = " << m_nMaxCols;
- dc << "\nm_nRows = " << m_nRows;
- dc << "\nm_nCols = " << m_nCols;
- dc << "\nm_bHasHScroll = " << m_bHasHScroll;
- dc << "\nm_bHasVScroll = " << m_bHasVScroll;
- dc << "\nm_cxSplitter = " << m_cxSplitter;
- dc << "\nm_cySplitter = " << m_cySplitter;
- if (m_bTracking)
- {
- dc << "\nTRACKING: m_htTrack = " << m_htTrack;
- dc << "\nm_rectLimit = " << m_rectLimit;
- dc << "\nm_ptTrackOffset = " << m_ptTrackOffset;
- dc << "\nm_rectTracker = " << m_rectTracker;
- if (m_bTracking2)
- dc << "\nm_rectTracker2 = " << m_rectTracker2;
- }
-
- dc << "\n";
- }
- #endif
-
- /////////////////////////////////////////////////////////////////////////////
-