home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-02-08 | 45.1 KB | 1,699 lines |
- // This is a part of the Microsoft Foundation Classes C++ library.
- // Copyright (C) 1992 Microsoft Corporation
- // All rights reserved.
- //
- // This source code is only intended as a supplement to the
- // Microsoft Foundation Classes Reference and Microsoft
- // QuickHelp and/or WinHelp documentation provided with the library.
- // See these sources for detailed information regarding the
- // Microsoft Foundation Classes product.
-
-
- #include "stdafx.h"
- #include <limits.h>
-
- #ifdef AFX_CORE3_SEG
- #pragma code_seg(AFX_CORE3_SEG)
- #endif
-
- #ifdef _DEBUG
- #undef THIS_FILE
- static char BASED_CODE 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_CANCELMODE()
- ON_WM_KEYDOWN()
- ON_WM_SIZE()
- ON_WM_HSCROLL()
- ON_WM_VSCROLL()
- //}}AFX_MSG_MAP
- END_MESSAGE_MAP()
-
- /////////////////////////////////////////////////////////////////////////////
- // CSplitterWnd construction/destruction
-
- // size of splitter gaps
- // (all panes must have borders - even if client area of pane is 0 pixels wide)
- #define CX_SPLITTER_GAP (CX_BORDER + m_cxSplitter + CX_BORDER)
- #define CY_SPLITTER_GAP (CY_BORDER + m_cySplitter + CY_BORDER)
-
- CSplitterWnd::CSplitterWnd()
- {
- AFX_ZERO_INIT_OBJECT(CWnd);
- // default splitter box/bar size (includes border)
- m_cxSplitter = m_cySplitter = 4;
- if (GetSystemMetrics(SM_CXBORDER) != CX_BORDER ||
- GetSystemMetrics(SM_CYBORDER) != CY_BORDER)
- {
- TRACE0("Warning: CSplitterWnd assumes 1 pixel border\n");
- // will look ugly if borders are not 1 pixel wide and 1 pixel high
- }
- }
-
- CSplitterWnd::~CSplitterWnd()
- {
- delete m_pRowInfo;
- delete m_pColInfo;
- }
-
- BOOL CSplitterWnd::Create(CWnd* pParentWnd,
- int nMaxRows, int nMaxCols, SIZE sizeMin,
- CCreateContext* pContext,
- DWORD dwStyle /* ... | SPLS_DYNAMIC_SPLIT */,
- UINT nID /* = AFX_IDW_PANE_FIRST */)
- {
- 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
-
- 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 /* = WS_CHILD | WS_VISIBLE */,
- UINT nID /* = AFX_IDW_PANE_FIRST */)
- {
- 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 no the smart scrollbars
- m_bHasHScroll = (dwStyle & WS_HSCROLL) != 0;
- m_bHasVScroll = (dwStyle & WS_VSCROLL) != 0;
- dwStyle &= ~(WS_HSCROLL|WS_VSCROLL);
-
- // create with the same wnd-class as MDI-Frame (no erase bkgnd)
- if (!CreateEx(0, _afxWndMDIFrame, NULL, dwStyle, 0, 0, 0, 0,
- pParentWnd->m_hWnd, (HMENU)nID, NULL))
- return FALSE; // create invisible
-
- // attach the initial splitter parts
- TRY
- {
- int row;
- int col;
-
- m_pColInfo = new CRowColInfo[m_nMaxCols];
- for (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 (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
- }
-
- if (m_bHasHScroll)
- for (col = 0; col < m_nCols; col++)
- if (!CreateScrollBarCtrl(SBS_HORZ, AFX_IDW_HSCROLL_FIRST + col))
- AfxThrowResourceException();
- if (m_bHasVScroll)
- for (row = 0; row < m_nRows; row++)
- if (!CreateScrollBarCtrl(SBS_VERT, AFX_IDW_VSCROLL_FIRST + row))
- AfxThrowResourceException();
-
- if (m_bHasHScroll && m_bHasVScroll)
- if (!CreateScrollBarCtrl(SBS_SIZEBOX|WS_DISABLED, AFX_IDW_SIZE_BOX))
- AfxThrowResourceException();
- }
- CATCH_ALL(e)
- {
- DestroyWindow(); // will clean up child windows
- return FALSE;
- }
- END_CATCH_ALL
-
- 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(AfxIsValidAddress(pViewClass, sizeof(CRuntimeClass)));
-
- 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 = GetParentFrame()->GetActiveView();
- if (pOldView != NULL)
- {
- // 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();
- ASSERT(pWnd != NULL);
- }
- CATCH_ALL(e)
- {
- TRACE0("Out of memory creating a splitter pane\n");
- return FALSE;
- }
- END_CATCH_ALL
-
- ASSERT(pWnd->IsKindOf(RUNTIME_CLASS(CWnd)));
- ASSERT(pWnd->m_hWnd == NULL); // not yet created
-
- // Create with the right size (wrong position)
- CRect rect(CPoint(0,0), sizeInit);
- if (!pWnd->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,
- 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);
-
- return (::CreateWindow("SCROLLBAR", NULL, dwStyle | WS_VISIBLE | WS_CHILD,
- 0, 0, 1, 1, m_hWnd, (HMENU)nID,
- AfxGetInstanceHandle(), NULL) != 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& row, int& col)
- {
- 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)
- {
- row = (nID - AFX_IDW_PANE_FIRST) / 16;
- col = (nID - AFX_IDW_PANE_FIRST) % 16;
- return TRUE;
- }
- else
- {
- row = col = -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_nRows);
-
- 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_nRows);
- 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_nCols);
-
- 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_nCols);
-
- m_pColInfo[col].nIdealSize = cxIdeal;
- m_pColInfo[col].nMinSize = cxMin;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // 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(pPane->IsKindOf(RUNTIME_CLASS(CView)));
- ASSERT(GetParentFrame() != NULL);
- if (GetParentFrame()->GetActiveView() == 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)
- {
- InvalidateRect(rectArg);
- return;
- }
- ASSERT_VALID(pDC);
-
- // otherwise actually draw
- CRect rect = rectArg;
- HGDIOBJ hOldBrush;
- if (nType == splitIntersection)
- {
- // prepare to fill the entire interesection
- hOldBrush = pDC->SelectObject(afxData.hbrLtGray);
- }
- else
- {
- // bar or box drawn the same
- // top or left hilite for 3D look
- pDC->PatBlt(rect.left, rect.top, rect.Width(), 1, WHITENESS);
- pDC->PatBlt(rect.left, rect.top, 1, rect.Height(), WHITENESS);
-
- // bottom or right shadow for 3D look
- hOldBrush = pDC->SelectObject(afxData.hbrDkGray);
- pDC->PatBlt(rect.right - 1, rect.top, 1, rect.Height(), PATCOPY);
- pDC->PatBlt(rect.left, rect.bottom - 1, rect.Width(), 1, PATCOPY);
-
- // prepare to fill the rest with gray
- pDC->SelectObject(afxData.hbrLtGray);
- rect.InflateRect(-1, -1);
- }
- // fill the middle
- pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATCOPY);
- pDC->SelectObject(hOldBrush);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // Dynamic row/col split etc
-
- static int NEAR PASCAL CanSplitRowCol(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);
-
- int rowNew = m_nRows;
- int cyNew = CanSplitRowCol(&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);
-
- int colNew = m_nCols;
- int cxNew = CanSplitRowCol(&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 row)
- {
- ASSERT_VALID(this);
- ASSERT(GetStyle() & SPLS_DYNAMIC_SPLIT);
-
- // default implementation deletes last row only
- ASSERT(m_nRows > 1);
- row = m_nRows - 1;
- for (int col = 0; col < m_nCols; col++)
- DeleteView(row, col);
- if (m_bHasVScroll)
- GetDlgItem(AFX_IDW_VSCROLL_FIRST + row)->DestroyWindow();
- m_nRows--;
- RecalcLayout(); // re-assign the space
- }
-
- void CSplitterWnd::DeleteColumn(int col)
- {
- ASSERT_VALID(this);
- ASSERT(GetStyle() & SPLS_DYNAMIC_SPLIT);
-
- // default implementation deletes last column only
- ASSERT(m_nCols > 1);
- col = m_nCols - 1;
- for (int row = 0; row < m_nRows; row++)
- DeleteView(row, col);
- if (m_bHasHScroll)
- GetDlgItem(AFX_IDW_HSCROLL_FIRST + col)->DestroyWindow();
- m_nCols--;
- 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 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;
-
- GetInsideRect(m_rectLimit);
- // GetHitRect will restrict 'm_rectLimit' as appropriate
-
- 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);
- m_bTracking2 = TRUE;
- GetHitRect(col + hSplitterBar1, m_rectTracker2);
- m_ptTrackOffset.x = -(m_cxSplitter/2);
- m_ptTrackOffset.y = -(m_cySplitter/2);
- }
- else if (ht == bothSplitterBox)
- {
- GetHitRect(vSplitterBox, m_rectTracker);
- m_bTracking2 = TRUE;
- GetHitRect(hSplitterBox, m_rectTracker2);
- }
- else
- {
- GetHitRect(ht, m_rectTracker);
- }
-
- // adjust for border size
- m_rectLimit.right -= CX_BORDER;
- m_rectLimit.bottom -= CY_BORDER;
-
- SetCapture();
- SetFocus();
-
- m_bTracking = TRUE;
- OnInvertTracker(m_rectTracker);
- if (m_bTracking2)
- OnInvertTracker(m_rectTracker2);
- m_htTrack = 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);
- }
- }
-
-
- 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);
- }
- }
-
-
- 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
- CFrameWnd* pParent = GetParentFrame();
- ASSERT(pParent != NULL); // must be in a frame
- CView* pOldActiveView = pParent->GetActiveView();
-
- // m_rectTracker is set to the new splitter position (without border)
- m_rectTracker.left -= CX_BORDER;
- m_rectTracker.top -= CY_BORDER;
- // adjust relative to where the border will be
-
- 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 == pParent->GetActiveView())
- pParent->SetActiveView(pOldActiveView); // re-activate
- }
-
-
- void CSplitterWnd::GetHitRect(int ht, CRect& rectHit)
- {
- ASSERT_VALID(this);
-
- CRect rectClient;
- GetClientRect(&rectClient);
- ASSERT(rectClient.left == 0 && rectClient.top == 0);
- int cx = rectClient.right;
- int cy = rectClient.bottom;
- int x = 0;
- int y = 0;
-
- // 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;
- m_ptTrackOffset.y = -(cy/2);
- ASSERT(m_rectLimit.top == 0);
- ASSERT(m_pRowInfo[0].nCurSize > 0);
- m_rectLimit.bottom += m_ptTrackOffset.y - CY_BORDER;
- }
- else if (ht == hSplitterBox)
- {
- cx = m_cxSplitter;
- m_ptTrackOffset.x = -(cx/2);
- ASSERT(m_rectLimit.left == 0);
- ASSERT(m_pColInfo[0].nCurSize > 0);
- m_rectLimit.right += m_ptTrackOffset.x - CX_BORDER;
- }
- else if (ht >= vSplitterBar1 && ht <= vSplitterBar15)
- {
- cy = m_cySplitter;
- m_ptTrackOffset.y = -(cy/2);
- for (int row = 0; row < ht - vSplitterBar1; row++)
- y += m_pRowInfo[row].nCurSize + CY_SPLITTER_GAP;
- m_rectLimit.top = y;
- y += m_pRowInfo[row].nCurSize + CY_BORDER;
- m_rectLimit.bottom += m_ptTrackOffset.y - CY_BORDER;
- }
- else if (ht >= hSplitterBar1 && ht <= hSplitterBar15)
- {
- cx = m_cxSplitter;
- m_ptTrackOffset.x = -(cx/2);
- for (int col = 0; col < ht - hSplitterBar1; col++)
- x += m_pColInfo[col].nCurSize + CX_SPLITTER_GAP;
- m_rectLimit.left = x;
- x += m_pColInfo[col].nCurSize + CX_BORDER;
- m_rectLimit.right += m_ptTrackOffset.x - CX_BORDER;
- }
- 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);
- ASSERT(rectClient.left == 0 && rectClient.top == 0);
-
- if (m_bHasVScroll && m_nRows < m_nMaxRows &&
- CRect(rectClient.right - afxData.cxVScroll, 0,
- rectClient.right, m_cySplitter + CY_BORDER).PtInRect(pt))
- {
- return vSplitterBox;
- }
-
- if (m_bHasHScroll && m_nCols < m_nMaxCols &&
- CRect(0, rectClient.bottom - afxData.cyHScroll,
- m_cxSplitter + CX_BORDER, rectClient.bottom).PtInRect(pt))
- {
- return hSplitterBox;
- }
-
- // for hit detect, include the border of splitters
- CRect rect;
- rect = rectClient;
- rect.left = 0;
- for (int col = 0; col < m_nCols - 1; col++)
- {
- rect.left += m_pColInfo[col].nCurSize;
- rect.right = rect.left + CX_SPLITTER_GAP;
- if (rect.PtInRect(pt))
- break;
- rect.left = rect.right;
- }
-
- rect = rectClient;
- rect.top = 0;
- for (int row = 0; row < m_nRows - 1; row++)
- {
- rect.top += m_pRowInfo[row].nCurSize;
- rect.bottom = rect.top + CY_SPLITTER_GAP;
- 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;
- }
-
- void CSplitterWnd::OnInvertTracker(const CRect& rect)
- {
- ASSERT_VALID(this);
- ASSERT(!rect.IsRectEmpty());
- ASSERT((GetStyle() & WS_CLIPCHILDREN) == 0);
-
- // pat-blt without clip children on
- CClientDC dc(this);
- dc.PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), DSTINVERT);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // 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
-
- // move the mouse cursor to the center of the client rect
- CRect rect;
- GetClientRect(&rect);
- ClientToScreen(&rect);
- ::SetCursorPos(rect.left + rect.Width() / 2, rect.top + rect.Height() / 2);
-
- // start tracking
- StartTracking(ht);
- return TRUE;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // Main drawing and layout
-
- 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
- static void NEAR PASCAL 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 + CX_BORDER
- // add remaining size and remove the extra border
- ASSERT(CX_BORDER == CY_BORDER);
- (pInfo-1)->nCurSize += nSize + CX_BORDER;
- 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 == CY_BORDER);
- pInfo->nCurSize += nSize;
- if (pInfo->nCurSize > (nSizeSplitter-CX_BORDER))
- pInfo->nCurSize -= (nSizeSplitter-CX_BORDER);
- 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)
- static HDWP NEAR PASCAL DeferClientPos(HDWP hDWP, 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
- DWORD dwStyle = pWnd->GetStyle();
- BOOL bNeedBorder = (cx <= CX_BORDER || cy <= CY_BORDER);
- if (bNeedBorder)
- dwStyle |= WS_BORDER;
- else
- dwStyle &= ~WS_BORDER;
- ::SetWindowLong(pWnd->m_hWnd, GWL_STYLE, dwStyle);
- }
-
- // adjust for border size (even if zero client size)
- x -= CX_BORDER;
- y -= CY_BORDER;
- cx += 2 * CX_BORDER;
- cy += 2 * CY_BORDER;
-
- // first check if the new rectangle is the same as the current
- CRect rectOld;
- pWnd->GetWindowRect(rectOld);
- pWnd->GetParent()->ScreenToClient(&rectOld);
- if (rectOld.left == x && rectOld.top == y &&
- rectOld.Width() == cx && rectOld.Height() == cy)
- {
- return hDWP; // nothing to do
- }
-
- return ::DeferWindowPos(hDWP, pWnd->m_hWnd, NULL,
- x, y, cx, cy, SWP_NOZORDER | SWP_NOACTIVATE);
- }
-
- void CSplitterWnd::RecalcLayout()
- {
- ASSERT_VALID(this);
- ASSERT(m_nRows > 0 && m_nCols > 0);
- // must have at least one pane
-
- CRect rectInside;
- GetInsideRect(rectInside);
-
- // layout columns (restrict to possible sizes)
- LayoutRowCol(m_pColInfo, m_nCols, rectInside.right, CX_SPLITTER_GAP);
- LayoutRowCol(m_pRowInfo, m_nRows, rectInside.bottom, CY_SPLITTER_GAP);
-
- // adjust the panes (and optionally scroll bars)
-
- // give the hint for the maximum number of HWNDs
- HDWP hDWP = ::BeginDeferWindowPos((m_nCols + 1) * (m_nRows + 1));
-
- // reposition size box
- if (m_bHasHScroll && m_bHasVScroll)
- {
- CWnd* pScrollBar = GetDlgItem(AFX_IDW_SIZE_BOX);
- ASSERT(pScrollBar != NULL);
- hDWP = ::DeferWindowPos(hDWP,
- pScrollBar->m_hWnd, NULL,
- rectInside.right, rectInside.bottom,
- afxData.cxVScroll, afxData.cyHScroll,
- SWP_NOZORDER | SWP_NOACTIVATE);
- }
-
- // reposition scroll bars
- if (m_bHasHScroll)
- {
- int ySB = rectInside.bottom + CY_BORDER;
- int x = 0;
- 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 += m_cxSplitter + CX_BORDER;
- cx -= m_cxSplitter + CX_BORDER;
- }
- hDWP = DeferClientPos(hDWP, pScrollBar, x, ySB,
- cx, afxData.cyHScroll - 2 * CY_BORDER, TRUE);
- x += cx + CX_SPLITTER_GAP;
- }
- }
-
- if (m_bHasVScroll)
- {
- int xSB = rectInside.right + CX_BORDER;
- int y = 0;
- 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 += m_cySplitter + CY_BORDER;
- cy -= m_cySplitter + CY_BORDER;
- }
- hDWP = DeferClientPos(hDWP, pScrollBar, xSB, y,
- afxData.cxVScroll - 2 * CX_BORDER, cy, TRUE);
- y += cy + CY_SPLITTER_GAP;
- }
- }
-
- //BLOCK: Reposition all the panes
- {
- int x = 0;
- for (int col = 0; col < m_nCols; col++)
- {
- int cx = m_pColInfo[col].nCurSize;
- int y = 0;
- for (int row = 0; row < m_nRows; row++)
- {
- int cy = m_pRowInfo[row].nCurSize;
- hDWP = DeferClientPos(hDWP, GetPane(row, col), x, y, cx, cy,
- FALSE);
- y += cy + CY_SPLITTER_GAP;
- }
- x += cx + CX_SPLITTER_GAP;
- }
- }
-
- // move them all
- if (hDWP == NULL)
- {
- TRACE0("Warning: low system resources, "
- "cannot reposition splitter panes\n");
- }
- ::EndDeferWindowPos(hDWP);
-
- DrawAllSplitBars(NULL, rectInside.right, rectInside.bottom);
- // NULL pDC just invalidates
- }
-
- void CSplitterWnd::DrawAllSplitBars(CDC* pDC, int cxInside, int cyInside)
- {
- ASSERT_VALID(this);
-
- CRect rect;
- GetClientRect(rect);
- for (int col = 0; col < m_nCols - 1; col++)
- {
- rect.left += m_pColInfo[col].nCurSize + CX_BORDER;
- rect.right = rect.left + m_cxSplitter;
- if (rect.right > cxInside)
- break; // stop if not fully visible
- OnDrawSplitter(pDC, splitBar, rect);
- rect.left = rect.right + CX_BORDER;
- }
-
- GetClientRect(rect);
- for (int row = 0; row < m_nRows - 1; row++)
- {
- rect.top += m_pRowInfo[row].nCurSize + CY_BORDER;
- rect.bottom = rect.top + m_cySplitter;
- if (rect.bottom > cyInside)
- break; // stop if not fully visible
- OnDrawSplitter(pDC, splitBar, rect);
- rect.top = rect.bottom + CY_BORDER;
- }
- }
-
- void CSplitterWnd::OnPaint()
- {
- ASSERT_VALID(this);
- CPaintDC dc(this);
-
- CRect rectClient;
- GetClientRect(&rectClient);
- CRect rectInside;
- GetInsideRect(rectInside);
-
- // draw the splitter boxes
- if (m_bHasVScroll && m_nRows < m_nMaxRows)
- {
- OnDrawSplitter(&dc, splitBox,
- CRect(rectInside.right + CX_BORDER, 0,
- rectClient.right, m_cySplitter));
- }
-
- if (m_bHasHScroll && m_nCols < m_nMaxCols)
- {
- OnDrawSplitter(&dc, splitBox,
- CRect(0, rectInside.bottom + CY_BORDER,
- m_cxSplitter, rectClient.bottom));
- }
-
- DrawAllSplitBars(&dc, rectInside.right, rectInside.bottom);
-
- dc.IntersectClipRect(rectInside);
- // draw splitter intersections (inside only)
- CRect rect;
- rect.top = 0;
- for (int row = 0; row < m_nRows - 1; row++)
- {
- rect.top += m_pRowInfo[row].nCurSize + CX_BORDER;
- rect.bottom = rect.top + m_cySplitter;
- rect.left = 0;
- for (int col = 0; col < m_nCols - 1; col++)
- {
- rect.left += m_pColInfo[col].nCurSize + CY_BORDER;
- rect.right = rect.left + m_cxSplitter;
- OnDrawSplitter(&dc, splitIntersection, rect);
- rect.left = rect.right + CY_BORDER;
- }
- rect.top = rect.bottom + CX_BORDER;
- }
- }
-
- BOOL CSplitterWnd::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
- {
- if (pWnd == this && !m_bTracking)
- return TRUE; // we will handle it in the mouse move
- return CWnd::OnSetCursor(pWnd, nHitTest, message);
- }
-
-
- void CSplitterWnd::OnMouseMove(UINT /*nFlags*/, CPoint pt)
- {
- // cache of last needed cursor
- static HCURSOR NEAR hcurLast = NULL;
- static HCURSOR NEAR hcurDestroy = NULL;
- static UINT NEAR idcPrimaryLast = 0; // store the primary IDC
-
- if (m_bTracking)
- {
- 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)
- {
- OnInvertTracker(m_rectTracker);
- m_rectTracker.top = pt.y;
- m_rectTracker.bottom = pt.y + m_cySplitter;
- OnInvertTracker(m_rectTracker);
- }
- else if (m_htTrack == hSplitterBox ||
- m_htTrack >= hSplitterBar1 && m_htTrack <= hSplitterBar15)
- {
- OnInvertTracker(m_rectTracker);
- m_rectTracker.left = pt.x;
- m_rectTracker.right = pt.x + m_cxSplitter;
- OnInvertTracker(m_rectTracker);
- }
- else if (m_htTrack == bothSplitterBox ||
- (m_htTrack >= splitterIntersection1 &&
- m_htTrack <= splitterIntersection225))
- {
- OnInvertTracker(m_rectTracker);
- m_rectTracker.top = pt.y;
- m_rectTracker.bottom = pt.y + m_cySplitter;
- OnInvertTracker(m_rectTracker);
-
- OnInvertTracker(m_rectTracker2);
- m_rectTracker2.left = pt.x;
- m_rectTracker2.right = pt.x + m_cxSplitter;
- OnInvertTracker(m_rectTracker2);
- }
- }
- else
- {
- int ht = HitTest(pt);
- UINT idcPrimary; // app supplied cursor
- LPCSTR idcSecondary; // system supplied cursor (MAKEINTRESOURCE)
-
- 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_SIZE;
- }
- else
- {
- SetCursor(afxData.hcurArrow);
- idcPrimary = 0; // don't use it
- idcSecondary = 0; // don't use it
- }
-
- if (idcPrimary != 0)
- {
- HCURSOR hcurToDestroy = NULL;
- if (idcPrimary != idcPrimaryLast)
- {
- #ifndef _AFXDLL
- HINSTANCE hInst = AfxGetResourceHandle();
- #else
- HINSTANCE hInst = AfxFindResourceHandle(
- MAKEINTRESOURCE(idcPrimary), RT_GROUP_CURSOR);
- #endif
- // load in another cursor
- hcurToDestroy = hcurDestroy;
- if ((hcurDestroy = hcurLast =
- ::LoadCursor(hInst, MAKEINTRESOURCE(idcPrimary))) == NULL)
- {
- // will no look as good
- TRACE0("Warning: Could not find splitter cursor -"
- " using system provided alternative\n");
-
- ASSERT(hcurDestroy == NULL); // will not get destroyed
- hcurLast = ::LoadCursor(NULL, idcSecondary);
- ASSERT(hcurLast != NULL);
- }
- idcPrimaryLast = idcPrimary;
- }
- ASSERT(hcurLast != NULL);
- ::SetCursor(hcurLast);
- ASSERT(hcurLast != hcurToDestroy);
- if (hcurToDestroy != NULL)
- ::DestroyCursor(hcurToDestroy); // destroy after being set
- }
- }
- }
-
-
- void CSplitterWnd::OnLButtonDown(UINT /*nFlags*/, CPoint pt)
- {
- 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)
- {
- // delete the row
- DeleteRow(ht - vSplitterBar1);
- }
- else if (ht >= hSplitterBar1 && ht <= hSplitterBar15)
- {
- DeleteColumn(ht - hSplitterBar1);
- }
- else if (ht >= splitterIntersection1 && ht <= splitterIntersection225)
- {
- int row = (ht - splitterIntersection1) / 15;
- int col = (ht - splitterIntersection1) % 15;
- DeleteRow(row);
- DeleteColumn(col);
- }
- }
-
-
- 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;
- int cz;
-
- GetCursorPos(&pt);
- cz = GetKeyState(VK_CONTROL) < 0 ? 1 : 16;
-
- switch (nChar)
- {
- case VK_ESCAPE:
- StopTracking(FALSE);
- break;
-
- case VK_RETURN:
- StopTracking(TRUE);
- break;
-
- case VK_LEFT:
- SetCursorPos(pt.x - cz, pt.y);
- break;
-
- case VK_RIGHT:
- SetCursorPos(pt.x + cz, pt.y);
- break;
-
- case VK_UP:
- SetCursorPos(pt.x, pt.y - cz);
- break;
-
- case VK_DOWN:
- SetCursorPos(pt.x, pt.y + cz);
- break;
-
- default:
- Default(); // pass other keys through
- break;
- }
- }
-
-
- /////////////////////////////////////////////////////////////////////////////
- // Scroll messages
-
-
- 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();
- int nNewPos;
- for (int row = 0; row < m_nRows; row++)
- {
- GetPane(row, col)->SendMessage(WM_HSCROLL, nSBCode,
- MAKELONG(nPos, pScrollBar->m_hWnd));
- if (row == 0)
- nNewPos = pScrollBar->GetScrollPos();
- #ifdef _DEBUG
- 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();
- int nNewPos;
- for (int col = 0; col < m_nCols; col++)
- {
- GetPane(row, col)->SendMessage(WM_VSCROLL, nSBCode,
- MAKELONG(nPos, pScrollBar->m_hWnd));
- if (col == 0)
- nNewPos = pScrollBar->GetScrollPos();
- #ifdef _DEBUG
- 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);
- }
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // Focus control and control over the current pane/child
-
- BOOL CSplitterWnd::CanActivateNext(BOOL)
- {
- ASSERT_VALID(this);
-
- ASSERT(GetParentFrame() != NULL);
- if (GetParentFrame()->GetActiveView() == 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);
-
- CFrameWnd* pFrame = GetParentFrame();
- ASSERT(pFrame != NULL);
-
- CView* pActiveView = pFrame->GetActiveView();
- if (pActiveView == NULL)
- {
- TRACE0("Warning: Cannot go to next pane - there is no current view\n");
- return;
- }
- // find the coordinate of the current pane
- int row, col;
- if (!IsChildPane(pActiveView, row, col))
- {
- TRACE0("Warning: Cannot go to next pane - active view is not a pane\n");
- return;
- }
- ASSERT(row >= 0 && row < m_nRows);
- ASSERT(col >= 0 && col < m_nCols);
-
- 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;
- }
- }
-
- CWnd* pNextPane = GetPane(row, col);
- if (pNextPane->IsKindOf(RUNTIME_CLASS(CView)))
- pFrame->SetActiveView((CView*)pNextPane);
- else
- TRACE0("Warning: Cannot go to next pane - next pane is not a CView\n");
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // 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
- {
- ASSERT_VALID(this);
-
- CWnd::Dump(dc);
- if (m_pDynamicViewClass == NULL)
- AFX_DUMP0(dc, "\nm_pDynamicViewClass = NULL");
- else
- AFX_DUMP1(dc, "\nm_pDynamicViewClass = ", m_pDynamicViewClass->m_lpszClassName);
- AFX_DUMP1(dc, "\nm_nMaxRows = ", m_nMaxRows);
- AFX_DUMP1(dc, "\nm_nMaxCols = ", m_nMaxCols);
- AFX_DUMP1(dc, "\nm_nRows = ", m_nRows);
- AFX_DUMP1(dc, "\nm_nCols = ", m_nCols);
- AFX_DUMP1(dc, "\nm_bHasHScroll = ", m_bHasHScroll);
- AFX_DUMP1(dc, "\nm_bHasVScroll = ", m_bHasVScroll);
- AFX_DUMP1(dc, "\nm_cxSplitter = ", m_cxSplitter);
- AFX_DUMP1(dc, "\nm_cySplitter = ", m_cySplitter);
- if (m_bTracking)
- {
- AFX_DUMP1(dc, "\nTRACKING: m_htTrack = ", m_htTrack);
- AFX_DUMP1(dc, "\nm_rectLimit = ", m_rectLimit);
- AFX_DUMP1(dc, "\nm_ptTrackOffset = ", m_ptTrackOffset);
- AFX_DUMP1(dc, "\nm_rectTracker = ", m_rectTracker);
- if (m_bTracking2)
- AFX_DUMP1(dc, "\nm_rectTracker2 = ", m_rectTracker2);
- }
- }
- #endif
-
- /////////////////////////////////////////////////////////////////////////////
-