XTSplitterWnd.cpp
上传用户:szled88
上传日期:2015-04-09
资源大小:43957k
文件大小:33k
源码类别:

对话框与窗口

开发平台:

Visual C++

  1. // SplitterWndXT.cpp : implementation file
  2. //
  3. // This file is a part of the XTREME CONTROLS MFC class library.
  4. // (c)1998-2008 Codejock Software, All Rights Reserved.
  5. //
  6. // THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
  7. // RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
  8. // CONSENT OF CODEJOCK SOFTWARE.
  9. //
  10. // THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
  11. // IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
  12. // YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
  13. // SINGLE COMPUTER.
  14. //
  15. // CONTACT INFORMATION:
  16. // support@codejock.com
  17. // http://www.codejock.com
  18. //
  19. /////////////////////////////////////////////////////////////////////////////
  20. #include "stdafx.h"
  21. #include "Common/XTPColorManager.h"
  22. #include "Common/XTPSystemHelpers.h"
  23. #include "XTGlobal.h"
  24. #include "XTSplitterWnd.h"
  25. #include "XTSplitterWndTheme.h"
  26. #ifdef _DEBUG
  27. #define new DEBUG_NEW
  28. #undef THIS_FILE
  29. static char THIS_FILE[] = __FILE__;
  30. #endif
  31. /////////////////////////////////////////////////////////////////////////////
  32. // Visual attributes and other constants
  33. // HitTest return values (values and spacing between values is important)
  34. enum HitTestValue
  35. {
  36. noHit = 0,
  37. vSplitterBox = 1,
  38. hSplitterBox = 2,
  39. bothSplitterBox = 3, // just for keyboard
  40. vSplitterBar1 = 101,
  41. vSplitterBar15 = 115,
  42. hSplitterBar1 = 201,
  43. hSplitterBar15 = 215,
  44. splitterIntersection1 = 301,
  45. splitterIntersection225 = 525
  46. };
  47. /////////////////////////////////////////////////////////////////////////////
  48. // CXTSplitterWnd
  49. IMPLEMENT_THEME_HOST(CXTSplitterWnd)
  50. IMPLEMENT_THEME_REFRESH(CXTSplitterWnd, CSplitterWnd)
  51. CXTSplitterWnd::CXTSplitterWnd()
  52. : CXTThemeManagerStyleHost(GetThemeFactoryClass())
  53. {
  54. m_nHiddenCol = -1;
  55. m_nHiddenRow = -1;
  56. m_point = CPoint(-1, -1);
  57. m_dwxStyle = XT_SPLIT_NOFULLDRAG;
  58. m_bFlatSplit = TRUE;
  59. m_cxSplitter = 6;
  60. m_cySplitter = 6;
  61. m_cxSplitterGap = 6;
  62. m_cySplitterGap = 6;
  63. // Get system settings for full drag.
  64. ::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS,
  65. 0, &m_bFullDrag, 0);
  66. m_bForceFullDrag = FALSE;
  67. m_bClipStyles = FALSE;
  68. }
  69. CXTSplitterWnd::~CXTSplitterWnd()
  70. {
  71. }
  72. IMPLEMENT_DYNAMIC(CXTSplitterWnd, CSplitterWnd)
  73. BEGIN_MESSAGE_MAP(CXTSplitterWnd, CSplitterWnd)
  74. //{{AFX_MSG_MAP(CXTSplitterWnd)
  75. ON_WM_SETTINGCHANGE()
  76. ON_MESSAGE(WM_PRINTCLIENT, OnPrintClient)
  77. ON_WM_MOUSEMOVE()
  78. ON_WM_NCHITTEST_EX()
  79. ON_WM_LBUTTONUP()
  80. //}}AFX_MSG_MAP
  81. END_MESSAGE_MAP()
  82. /////////////////////////////////////////////////////////////////////////////
  83. // CXTSplitterWnd message handlers
  84. LRESULT CXTSplitterWnd::OnPrintClient(WPARAM wParam, LPARAM /*lParam*/)
  85. {
  86. CDC* pDC = CDC::FromHandle((HDC)wParam);
  87. if (pDC)
  88. {
  89. CRect rectClient;
  90. GetClientRect(&rectClient);
  91. rectClient.InflateRect(-m_cxBorder, -m_cyBorder);
  92. CRect rectInside;
  93. GetInsideRect(rectInside);
  94. // draw the splitter boxes
  95. if (m_bHasVScroll && m_nRows < m_nMaxRows)
  96. {
  97. OnDrawSplitter(pDC, splitBox,
  98. CRect(rectInside.right, rectClient.top,
  99. rectClient.right, rectClient.top + m_cySplitter));
  100. }
  101. if (m_bHasHScroll && m_nCols < m_nMaxCols)
  102. {
  103. OnDrawSplitter(pDC, splitBox,
  104. CRect(rectClient.left, rectInside.bottom,
  105. rectClient.left + m_cxSplitter, rectClient.bottom));
  106. }
  107. // extend split bars to window border (past margins)
  108. DrawAllSplitBars(pDC, rectInside.right, rectInside.bottom);
  109. }
  110. return TRUE;
  111. }
  112. void CXTSplitterWnd::ShowColumn()
  113. {
  114. ASSERT_VALID(this);
  115. if (m_nCols == m_nMaxCols && m_nHiddenCol == -1)
  116. {
  117. return;
  118. }
  119. ASSERT(m_nHiddenCol != -1);
  120. int nShowCol = m_nHiddenCol;
  121. m_nHiddenCol = -1;
  122. int cxNew = m_pColInfo[m_nCols].nCurSize;
  123. m_nCols++;  // add a column
  124. ASSERT(m_nCols == m_nMaxCols);
  125. int nCol;
  126. // Show the hidden column
  127. int nRow;
  128. for (nRow = 0; nRow < m_nRows; ++nRow)
  129. {
  130. int nShowRow = m_nHiddenRow != -1 && m_nHiddenRow <= nRow ? nRow + 1 : nRow;
  131. CWnd* pPaneShow = GetDlgItem(AFX_IDW_PANE_FIRST + nShowRow * 16 + m_nCols);
  132. ASSERT(pPaneShow != NULL);
  133. if (!pPaneShow)
  134. return;
  135. pPaneShow->ShowWindow(SW_SHOWNA);
  136. for (nCol = m_nCols - 2; nCol >= nShowCol; --nCol)
  137. {
  138. CWnd* pPane = GetPane(nRow, nCol);
  139. ASSERT(pPane != NULL);
  140. if (!pPane)
  141. return;
  142. pPane->SetDlgCtrlID(IdFromRowCol(nRow, nCol + 1));
  143. }
  144. pPaneShow->SetDlgCtrlID(IdFromRowCol(nRow, nShowCol));
  145. }
  146. if (m_nHiddenRow != -1)
  147. {
  148. CWnd* pPaneHide = GetDlgItem(AFX_IDW_PANE_FIRST + m_nHiddenRow * 16 + m_nCols);
  149. if (pPaneHide)
  150. {
  151. pPaneHide->SetDlgCtrlID(AFX_IDW_PANE_FIRST + m_nMaxRows * 16 + nShowCol);
  152. }
  153. }
  154. // new panes have been created -- recalculate layout
  155. for (nCol = nShowCol + 1; nCol < m_nCols; nCol++)
  156. m_pColInfo[nCol].nIdealSize = m_pColInfo[nCol - 1].nCurSize;
  157. m_pColInfo[nShowCol].nIdealSize = cxNew;
  158. RecalcLayout();
  159. }
  160. void CXTSplitterWnd::HideColumn(int nColHide)
  161. {
  162. ASSERT_VALID(this);
  163. if (m_nHiddenCol != -1)
  164. {
  165. // return if the requested one is hidden
  166. if (m_nHiddenCol == nColHide)
  167. {
  168. return;
  169. }
  170. ShowColumn();
  171. }
  172. ASSERT(m_nCols > 1);
  173. ASSERT(nColHide < m_nCols);
  174. ASSERT(m_nHiddenCol == -1);
  175. m_nHiddenCol = nColHide;
  176. // if the column has an active window -- change it
  177. int nActiveRow, nActiveCol;
  178. if (GetActivePane(&nActiveRow, &nActiveCol) != NULL)
  179. {
  180. if (nActiveCol == nColHide)
  181. {
  182. if (++nActiveCol >= m_nCols)
  183. nActiveCol = 0;
  184. SetActivePane(nActiveRow, nActiveCol);
  185. }
  186. }
  187. // hide all column panes
  188. int nRow;
  189. for (nRow = 0; nRow < m_nRows; nRow++)
  190. {
  191. CWnd* pPaneHide = GetPane(nRow, nColHide);
  192. ASSERT(pPaneHide != NULL);
  193. if (!pPaneHide)
  194. return;
  195. pPaneHide->ShowWindow(SW_HIDE);
  196. int nRowHide = m_nHiddenRow != -1 && m_nHiddenRow <= nRow ? nRow + 1 : nRow;
  197. pPaneHide->SetDlgCtrlID(AFX_IDW_PANE_FIRST + nRowHide * 16 + m_nCols);
  198. int nCol;
  199. for (nCol = nColHide + 1; nCol < m_nCols; nCol++)
  200. {
  201. CWnd* pPane = GetPane(nRow, nCol);
  202. ASSERT(pPane != NULL);
  203. if (!pPane)
  204. return;
  205. pPane->SetDlgCtrlID(IdFromRowCol(nRow, nCol - 1));
  206. }
  207. }
  208. m_nCols--;
  209. m_pColInfo[m_nCols].nCurSize = m_pColInfo[nColHide].nCurSize;
  210. RecalcLayout();
  211. }
  212. void CXTSplitterWnd::ShowRow()
  213. {
  214. ASSERT_VALID(this);
  215. if (m_nRows == m_nMaxRows && m_nHiddenRow == -1)
  216. {
  217. return;
  218. }
  219. ASSERT(m_nHiddenRow != -1);
  220. int nShowRow = m_nHiddenRow;
  221. m_nHiddenRow = -1;
  222. int cyNew = m_pRowInfo[m_nRows].nCurSize;
  223. m_nRows++;  // add a nRow
  224. ASSERT(m_nRows == m_nMaxRows);
  225. int nRow;
  226. // Show the hidden nRow
  227. int nCol;
  228. for (nCol = 0; nCol < m_nCols; ++nCol)
  229. {
  230. int nShowCol = m_nHiddenCol != -1 && m_nHiddenCol <= nCol ? nCol + 1 : nCol;
  231. CWnd* pPaneShow = GetDlgItem(AFX_IDW_PANE_FIRST + m_nRows * 16 + nShowCol);
  232. ASSERT(pPaneShow != NULL);
  233. if (!pPaneShow)
  234. return;
  235. pPaneShow->ShowWindow(SW_SHOWNA);
  236. for (nRow = m_nRows - 2; nRow >= nShowRow; --nRow)
  237. {
  238. CWnd* pPane = GetPane(nRow, nCol);
  239. ASSERT(pPane != NULL);
  240. if (!pPane)
  241. return;
  242. pPane->SetDlgCtrlID(IdFromRowCol(nRow + 1, nCol));
  243. }
  244. pPaneShow->SetDlgCtrlID(IdFromRowCol(nShowRow, nCol));
  245. }
  246. if (m_nHiddenCol != -1)
  247. {
  248. CWnd* pPaneHide = GetDlgItem(AFX_IDW_PANE_FIRST + m_nRows * 16 + m_nHiddenCol);
  249. if (pPaneHide)
  250. {
  251. pPaneHide->SetDlgCtrlID(AFX_IDW_PANE_FIRST + nShowRow * 16 + m_nMaxCols);
  252. }
  253. }
  254. // new panes have been created -- recalculate layout
  255. for (nRow = nShowRow + 1; nRow < m_nRows; nRow++)
  256. m_pRowInfo[nRow].nIdealSize = m_pRowInfo[nRow - 1].nCurSize;
  257. m_pRowInfo[nShowRow].nIdealSize = cyNew;
  258. RecalcLayout();
  259. }
  260. void CXTSplitterWnd::HideRow(int nRowHide)
  261. {
  262. ASSERT_VALID(this);
  263. if (m_nHiddenRow != -1)
  264. {
  265. // return if the requested one is hidden
  266. if (m_nHiddenRow == nRowHide)
  267. {
  268. return;
  269. }
  270. ShowRow();
  271. }
  272. ASSERT(m_nRows > 1);
  273. ASSERT(nRowHide < m_nRows);
  274. ASSERT(m_nHiddenRow == -1);
  275. m_nHiddenRow = nRowHide;
  276. int nActiveRow, nActiveCol;
  277. // if the nRow has an active window -- change it
  278. if (GetActivePane(&nActiveRow, &nActiveCol) != NULL)
  279. {
  280. if (nActiveRow == nRowHide)
  281. {
  282. if (++nActiveRow >= m_nRows)
  283. nActiveRow = 0;
  284. SetActivePane(nActiveRow, nActiveCol);
  285. }
  286. }
  287. // hide all nRow panes.
  288. int nCol;
  289. for (nCol = 0; nCol < m_nCols; ++nCol)
  290. {
  291. CWnd* pPaneHide = GetPane(nRowHide, nCol);
  292. ASSERT(pPaneHide != NULL);
  293. if (!pPaneHide)
  294. return;
  295. pPaneHide->ShowWindow(SW_HIDE);
  296. int nColHide = m_nHiddenCol != -1 && m_nHiddenCol <= nCol ? nCol + 1 : nCol;
  297. pPaneHide->SetDlgCtrlID(AFX_IDW_PANE_FIRST + m_nRows * 16 + nColHide);
  298. int nRow;
  299. for (nRow = nRowHide + 1; nRow < m_nRows; ++nRow)
  300. {
  301. CWnd* pPane = GetPane(nRow, nCol);
  302. ASSERT(pPane != NULL);
  303. if (!pPane)
  304. return;
  305. pPane->SetDlgCtrlID(IdFromRowCol(nRow-1, nCol));
  306. }
  307. }
  308. m_nRows--;
  309. m_pRowInfo[m_nRows].nCurSize = m_pRowInfo[nRowHide].nCurSize;
  310. RecalcLayout();
  311. }
  312. BOOL CXTSplitterWnd::SwitchView(int nRow, int nCol, CView* pNewView)
  313. {
  314. CView *pOldView = DYNAMIC_DOWNCAST(CView, GetPane(nRow, nCol));
  315. ASSERT_KINDOF(CView, pOldView);
  316. if (pOldView == pNewView)
  317. return FALSE;
  318. int nOldID = pOldView->GetDlgCtrlID();
  319. int nNewID = pNewView->GetDlgCtrlID();
  320. // hide the views.
  321. pOldView->ShowWindow(SW_HIDE);
  322. pNewView->ShowWindow(SW_HIDE);
  323. // swap ids.
  324. pOldView->SetDlgCtrlID(nNewID);
  325. pNewView->SetDlgCtrlID(nOldID);
  326. // show the views.
  327. pOldView->ShowWindow(SW_SHOW);
  328. pNewView->ShowWindow(SW_SHOW);
  329. RecalcLayout();
  330. return TRUE;
  331. }
  332. CView* CXTSplitterWnd::ReplaceView(int nRow, int nCol, CView* pNewView)
  333. {
  334. CView* pOldView = DYNAMIC_DOWNCAST(CView, GetPane (nRow, nCol));
  335. ASSERT_KINDOF (CView, pOldView);
  336. if (pOldView == pNewView)
  337. return NULL;
  338. int nCtrlID = pOldView->GetDlgCtrlID();
  339. // swap ids.
  340. pOldView->SetDlgCtrlID(0);
  341. pNewView->SetDlgCtrlID(nCtrlID);
  342. // show the views.
  343. pOldView->ShowWindow(SW_HIDE);
  344. pNewView->ShowWindow(SW_SHOW);
  345. RecalcLayout();
  346. return pOldView;
  347. }
  348. CView* CXTSplitterWnd::ReplaceView(int nRow, int nCol, CRuntimeClass* pViewClass)
  349. {
  350. CView* pOldView = DYNAMIC_DOWNCAST(CView, GetPane (nRow, nCol));
  351. ASSERT_KINDOF (CView, pOldView);
  352. if (pOldView->IsKindOf(pViewClass))
  353. return NULL;
  354. // Get pointer to CDocument object so that it can be used in the creation
  355. // process of the new view
  356. CDocument* pDocument = pOldView->GetDocument();
  357. int nCtrlID = pOldView->GetDlgCtrlID();
  358. int nWidth, nHeight, nMinWidth, nMinHeight;
  359. GetRowInfo(nRow, nWidth, nMinWidth);
  360. GetColumnInfo(nCol, nHeight, nMinHeight);
  361. // Create new view
  362. CCreateContext contextT;
  363. contextT.m_pLastView = NULL;
  364. contextT.m_pCurrentDoc = pDocument;
  365. contextT.m_pNewViewClass = pViewClass;
  366. contextT.m_pNewDocTemplate = pDocument ? pDocument->GetDocTemplate() : NULL;
  367. contextT.m_pCurrentFrame = NULL;
  368. CWnd* pWnd = NULL;
  369. TRY
  370. {
  371. pWnd = (CWnd*)pViewClass->CreateObject();
  372. if (pWnd == NULL)
  373. AfxThrowMemoryException();
  374. }
  375. CATCH_ALL(e)
  376. {
  377. TRACE0("Out of memory creating a view.n");
  378. // Note: DELETE_EXCEPTION(e) not required
  379. return NULL;
  380. }
  381. END_CATCH_ALL
  382. ASSERT_KINDOF(CWnd, pWnd);
  383. ASSERT(pWnd->m_hWnd == NULL); // not yet created.
  384. // Create with the right size (wrong position)
  385. if (!pWnd->Create(NULL, NULL, WS_CHILD | WS_VISIBLE,
  386. CRect(0, 0, 0, 0), this, nCtrlID, &contextT))
  387. {
  388. TRACE0("Warning: couldn't create new view.n");
  389. // pWnd will be cleaned up by PostNcDestroy
  390. return NULL;
  391. }
  392. // Hide the old view.
  393. pOldView->ShowWindow(SW_HIDE);
  394. pOldView->SetDlgCtrlID(0);
  395. SetRowInfo (nRow, nWidth, nMinWidth);
  396. SetColumnInfo (nCol, nHeight, nMinHeight);
  397. RecalcLayout ();
  398. CView* pNewView = DYNAMIC_DOWNCAST (CView, GetPane (nRow, nCol));
  399. ASSERT_KINDOF (CView, pNewView);
  400. pNewView->OnInitialUpdate();
  401. return pOldView;
  402. }
  403. void CXTSplitterWnd::SetSplitCursor(int ht)
  404. {
  405. if (ht == vSplitterBox || ht >= vSplitterBar1 && ht <= vSplitterBar15)
  406. {
  407. SetCursor(XTAuxData().hcurVSplitBar);
  408. }
  409. else if (ht == hSplitterBox || ht >= hSplitterBar1 && ht <= hSplitterBar15)
  410. {
  411. SetCursor(XTAuxData().hcurHSplitBar);
  412. }
  413. else
  414. {
  415. CSplitterWnd::SetSplitCursor(ht);
  416. }
  417. }
  418. void CXTSplitterWnd::OnSettingChange(UINT uFlags, LPCTSTR lpszSection)
  419. {
  420. CSplitterWnd::OnSettingChange(uFlags, lpszSection);
  421. if (!m_bForceFullDrag)
  422. {
  423. // Get system settings for full drag.
  424. ::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS,
  425. 0, &m_bFullDrag, 0);
  426. // Force no display of windows contents while dragging,
  427. // regardless of windows setting.
  428. if (m_dwxStyle & XT_SPLIT_NOFULLDRAG)
  429. {
  430. m_bFullDrag = FALSE;
  431. }
  432. }
  433. }
  434. void CXTSplitterWnd::SetFullDrag(BOOL bFullDrag)
  435. {
  436. m_bFullDrag = bFullDrag;
  437. m_bForceFullDrag = TRUE;
  438. }
  439. void CXTSplitterWnd::DrawTracker(const CRect& rect, CBrush* pBrush)
  440. {
  441. if (m_bFullDrag == FALSE)
  442. {
  443. ASSERT_VALID(this);
  444. ASSERT(!rect.IsRectEmpty());
  445. ASSERT((GetStyle() & WS_CLIPCHILDREN) == 0);
  446. CWindowDC dc(this);
  447. int nSavedDC = dc.SaveDC();
  448. if (m_dwxStyle & XT_SPLIT_DOTTRACKER)
  449. {
  450. CRect rc;
  451. GetInsideRect(rc);
  452. if (rect.Width() < rect.Height())
  453. {
  454. rc.right = rect.right;
  455. }
  456. else
  457. {
  458. rc.bottom = rect.top;
  459. }
  460. dc.DrawFocusRect(rc);
  461. }
  462. else
  463. {
  464. CRect rcTracker(&rect);
  465. BOOL bVert = rcTracker.Height() > rcTracker.Width();
  466. if (bVert)
  467. {
  468. if (rcTracker.Width() != 4)
  469. {
  470. rcTracker.left = rcTracker.right - 4;
  471. }
  472. }
  473. else
  474. {
  475. if (rcTracker.Height() != 4)
  476. {
  477. rcTracker.bottom = rcTracker.top + 4;
  478. }
  479. }
  480. dc.SelectObject(pBrush);
  481. dc.PatBlt(rcTracker.left, rcTracker.top, rcTracker.Width(), rcTracker.Height(), PATINVERT);
  482. }
  483. dc.RestoreDC(nSavedDC);
  484. }
  485. }
  486. void CXTSplitterWnd::OnInvertTracker(const CRect& rect)
  487. {
  488. CBrush* pBrush = NULL;
  489. if (m_bFlatSplit)
  490. {
  491. pBrush = CBrush::FromHandle((HBRUSH)::GetStockObject(WHITE_BRUSH));
  492. }
  493. else
  494. {
  495. pBrush = CDC::GetHalftoneBrush();
  496. }
  497. DrawTracker(rect, pBrush);
  498. }
  499. void CXTSplitterWnd::OnMouseMove(UINT nFlags, CPoint point)
  500. {
  501. if (m_bFullDrag == FALSE)
  502. {
  503. CSplitterWnd::OnMouseMove(nFlags, point);
  504. return;
  505. }
  506. if (GetCapture() != this)
  507. {
  508. StopTracking(FALSE);
  509. }
  510. if (m_bTracking)
  511. {
  512. // move tracker to current cursor position
  513. point.Offset(m_ptTrackOffset); // point is the upper right of hit detect
  514. // limit the point to the valid split range
  515. if (point.y < m_rectLimit.top)
  516. {
  517. point.y = m_rectLimit.top;
  518. }
  519. else if (point.y > m_rectLimit.bottom)
  520. {
  521. point.y = m_rectLimit.bottom;
  522. }
  523. if (point.x < m_rectLimit.left)
  524. {
  525. point.x = m_rectLimit.left;
  526. }
  527. else if (point.x > m_rectLimit.right)
  528. {
  529. point.x = m_rectLimit.right;
  530. }
  531. if (m_htTrack == vSplitterBox || m_htTrack >= vSplitterBar1 && m_htTrack <= vSplitterBar15)
  532. {
  533. if (m_rectTracker.top != point.y)
  534. {
  535. OnInvertTracker(m_rectTracker);
  536. m_rectTracker.OffsetRect(0, point.y - m_rectTracker.top);
  537. OnInvertTracker(m_rectTracker);
  538. }
  539. }
  540. else if (m_htTrack == hSplitterBox || m_htTrack >= hSplitterBar1 && m_htTrack <= hSplitterBar15)
  541. {
  542. if (m_rectTracker.left != point.x)
  543. {
  544. OnInvertTracker(m_rectTracker);
  545. m_rectTracker.OffsetRect(point.x - m_rectTracker.left, 0);
  546. OnInvertTracker(m_rectTracker);
  547. }
  548. }
  549. else if (m_htTrack == bothSplitterBox || (m_htTrack >= splitterIntersection1 && m_htTrack <= splitterIntersection225))
  550. {
  551. if (m_rectTracker.top != point.y)
  552. {
  553. OnInvertTracker(m_rectTracker);
  554. m_rectTracker.OffsetRect(0, point.y - m_rectTracker.top);
  555. OnInvertTracker(m_rectTracker);
  556. }
  557. if (m_rectTracker2.left != point.x)
  558. {
  559. OnInvertTracker(m_rectTracker2);
  560. m_rectTracker2.OffsetRect(point.x - m_rectTracker2.left, 0);
  561. OnInvertTracker(m_rectTracker2);
  562. }
  563. }
  564. OnLButtonUp(MK_LBUTTON, point);
  565. OnLButtonDown(MK_LBUTTON, point);
  566. if (m_point != point)
  567. {
  568. RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_UPDATENOW);
  569. m_point = point;
  570. }
  571. }
  572. else
  573. {
  574. // simply hit-test and set appropriate cursor
  575. int ht = HitTest(point);
  576. SetSplitCursor(ht);
  577. }
  578. }
  579. void CXTSplitterWnd::StartTracking(int ht)
  580. {
  581. m_bClipStyles = FALSE;
  582. if (!m_bFullDrag)
  583. {
  584. if (GetStyle() & WS_CLIPCHILDREN)
  585. {
  586. ModifyStyle(WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0);
  587. m_bClipStyles = TRUE;
  588. }
  589. CSplitterWnd::StartTracking(ht);
  590. return;
  591. }
  592. ASSERT_VALID(this);
  593. if (ht == noHit)
  594. {
  595. return;
  596. }
  597. // GetHitRect will restrict 'm_rectLimit' as appropriate
  598. GetInsideRect(m_rectLimit);
  599. if (ht >= splitterIntersection1 && ht <= splitterIntersection225)
  600. {
  601. // split two directions (two tracking rectangles)
  602. int row = (ht - splitterIntersection1) / 15;
  603. int col = (ht - splitterIntersection1) % 15;
  604. GetHitRect(row + vSplitterBar1, m_rectTracker);
  605. int yTrackOffset = m_ptTrackOffset.y;
  606. m_bTracking2 = TRUE;
  607. GetHitRect(col + hSplitterBar1, m_rectTracker2);
  608. m_ptTrackOffset.y = yTrackOffset;
  609. }
  610. else if (ht == bothSplitterBox)
  611. {
  612. // hit on splitter boxes (for keyboard)
  613. GetHitRect(vSplitterBox, m_rectTracker);
  614. int yTrackOffset = m_ptTrackOffset.y;
  615. m_bTracking2 = TRUE;
  616. GetHitRect(hSplitterBox, m_rectTracker2);
  617. m_ptTrackOffset.y = yTrackOffset;
  618. // center it
  619. m_rectTracker.OffsetRect(0, m_rectLimit.Height()/2);
  620. m_rectTracker2.OffsetRect(m_rectLimit.Width()/2, 0);
  621. }
  622. else
  623. {
  624. // only hit one bar
  625. GetHitRect(ht, m_rectTracker);
  626. }
  627. // steal focus and capture
  628. SetCapture();
  629. // set tracking state and appropriate cursor
  630. m_bTracking = TRUE;
  631. m_htTrack = ht;
  632. SetSplitCursor(ht);
  633. }
  634. void CXTSplitterWnd::StopTracking(BOOL bAccept)
  635. {
  636. if (!m_bFullDrag)
  637. {
  638. CSplitterWnd::StopTracking(bAccept);
  639. if (m_bClipStyles)
  640. {
  641. ModifyStyle(0, WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
  642. m_bClipStyles = FALSE;
  643. }
  644. return;
  645. }
  646. ASSERT_VALID(this);
  647. if (!m_bTracking)
  648. {
  649. return;
  650. }
  651. ReleaseCapture();
  652. // erase tracker rectangle
  653. OnInvertTracker(m_rectTracker);
  654. if (m_bTracking2)
  655. OnInvertTracker(m_rectTracker2);
  656. m_bTracking = m_bTracking2 = FALSE;
  657. // save old active view
  658. CWnd* pOldActiveView = GetActivePane();
  659. // m_rectTracker is set to the new splitter position (without border)
  660. // (so, adjust relative to where the border will be)
  661. m_rectTracker.OffsetRect(-CX_BORDER , -CY_BORDER);
  662. m_rectTracker2.OffsetRect(-CX_BORDER, -CY_BORDER);
  663. if (bAccept)
  664. {
  665. if (m_htTrack == vSplitterBox)
  666. {
  667. SplitRow(m_rectTracker.top);
  668. }
  669. else if (m_htTrack >= vSplitterBar1 && m_htTrack <= vSplitterBar15)
  670. {
  671. // adjust the tracking rect for flat splitter.
  672. if (m_bFlatSplit)
  673. {
  674. m_rectTracker.top = m_rectTracker.bottom - 4;
  675. }
  676. // set row height
  677. TrackRowSize(m_rectTracker.top, m_htTrack - vSplitterBar1);
  678. RecalcLayout();
  679. }
  680. else if (m_htTrack == hSplitterBox)
  681. {
  682. SplitColumn(m_rectTracker.left);
  683. }
  684. else if (m_htTrack >= hSplitterBar1 && m_htTrack <= hSplitterBar15)
  685. {
  686. // adjust the tracking rect for flat splitter.
  687. if (m_bFlatSplit)
  688. {
  689. m_rectTracker.left = m_rectTracker.right - 4;
  690. }
  691. // set column width
  692. TrackColumnSize(m_rectTracker.left, m_htTrack - hSplitterBar1);
  693. RecalcLayout();
  694. }
  695. else if (m_htTrack >= splitterIntersection1 &&
  696. m_htTrack <= splitterIntersection225)
  697. {
  698. // set row height and column width
  699. int row = (m_htTrack - splitterIntersection1) / 15;
  700. int col = (m_htTrack - splitterIntersection1) % 15;
  701. TrackRowSize(m_rectTracker.top, row);
  702. TrackColumnSize(m_rectTracker2.left, col);
  703. RecalcLayout();
  704. }
  705. else if (m_htTrack == bothSplitterBox)
  706. {
  707. // rectTracker is vSplitter (splits rows)
  708. // rectTracker2 is hSplitter (splits cols)
  709. SplitRow(m_rectTracker.top);
  710. SplitColumn(m_rectTracker2.left);
  711. }
  712. }
  713. if ((pOldActiveView == GetActivePane()) &&
  714. (pOldActiveView != NULL))
  715. {
  716. SetActivePane(-1, -1, pOldActiveView); // re-activate
  717. }
  718. }
  719. void CXTSplitterWnd::SetSplitterStyle(DWORD dwxStyle)
  720. {
  721. m_dwxStyle = dwxStyle;
  722. // Force no display of windows contents while dragging,
  723. // regardless of windows setting.
  724. if (m_dwxStyle & XT_SPLIT_NOFULLDRAG)
  725. {
  726. m_bFullDrag = FALSE;
  727. }
  728. else
  729. {
  730. // Get system settings for full drag.
  731. ::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS,
  732. 0, &m_bFullDrag, 0);
  733. }
  734. }
  735. LRESULT CXTSplitterWnd::OnNcHitTest(CPoint point)
  736. {
  737. // If XT_SPLIT_NOSIZE style is defined, just return a border
  738. // hit so can at least activate the app if needed.
  739. if ((m_dwxStyle & XT_SPLIT_NOSIZE) == XT_SPLIT_NOSIZE)
  740. {
  741. return HTBORDER;
  742. }
  743. return (LRESULT)CSplitterWnd::OnNcHitTest(point);
  744. }
  745. void CXTSplitterWnd::EnableFlatLook(BOOL bFlatSplitter)
  746. {
  747. m_bFlatSplit = bFlatSplitter;
  748. m_cxSplitter = m_bFlatSplit ? 6 : 7;
  749. m_cySplitter = m_bFlatSplit ? 6 : 7;
  750. m_cxSplitterGap = m_bFlatSplit ? 6 : 7;
  751. m_cySplitterGap = m_bFlatSplit ? 6 : 7;
  752. RecalcLayout();
  753. }
  754. void CXTSplitterWnd::OnDrawSplitter(CDC* pDC, ESplitType nType, const CRect& rectArg)
  755. {
  756. COLORREF clr3DFace = GetTheme()->m_clrSplitterFace;
  757. COLORREF clr3DShadow = GetTheme()->m_clrSplitterBorders;
  758. // if pDC == NULL, then just invalidate
  759. if (pDC == NULL)
  760. {
  761. RedrawWindow(rectArg, NULL, RDW_INVALIDATE | RDW_NOCHILDREN);
  762. return;
  763. }
  764. ASSERT_VALID(pDC);
  765. // otherwise, actually draw
  766. CRect rect = rectArg;
  767. switch (nType)
  768. {
  769. case splitBorder:
  770. if (m_bFlatSplit)
  771. {
  772. if (!(m_dwxStyle & XT_SPLIT_NOBORDER))
  773. {
  774. pDC->Draw3dRect(rect, clr3DFace, clr3DFace);
  775. rect.InflateRect(-CX_BORDER, -CY_BORDER);
  776. pDC->Draw3dRect(rect, clr3DShadow, GetXtremeColor(COLOR_3DHILIGHT));
  777. }
  778. else
  779. {
  780. pDC->Draw3dRect(rect, clr3DFace, clr3DFace);
  781. rect.InflateRect(-CX_BORDER, -CY_BORDER);
  782. pDC->Draw3dRect(rect, clr3DFace, clr3DFace);
  783. }
  784. }
  785. else
  786. {
  787. pDC->Draw3dRect(rect, clr3DShadow, GetXtremeColor(COLOR_3DHILIGHT));
  788. rect.InflateRect(-CX_BORDER, -CY_BORDER);
  789. pDC->Draw3dRect(rect, GetXtremeColor(COLOR_WINDOWFRAME), clr3DFace);
  790. }
  791. return;
  792. case splitIntersection:
  793. ASSERT(!XTOSVersionInfo()->IsWin95OrGreater());
  794. break;
  795. case splitBox:
  796. if (m_bFlatSplit)
  797. {
  798. pDC->Draw3dRect(rect, clr3DFace, clr3DFace);
  799. rect.InflateRect(-CX_BORDER, -CY_BORDER);
  800. pDC->Draw3dRect(rect, GetXtremeColor(COLOR_3DHILIGHT), clr3DShadow);
  801. rect.InflateRect(-CX_BORDER, -CY_BORDER);
  802. }
  803. else
  804. {
  805. pDC->Draw3dRect(rect, clr3DFace, GetXtremeColor(COLOR_WINDOWFRAME));
  806. rect.InflateRect(-CX_BORDER, -CY_BORDER);
  807. pDC->Draw3dRect(rect, GetXtremeColor(COLOR_3DHILIGHT), clr3DShadow);
  808. rect.InflateRect(-CX_BORDER, -CY_BORDER);
  809. }
  810. break;
  811. case splitBar:
  812. break;
  813. default:
  814. ASSERT(FALSE);  // unknown splitter type
  815. }
  816. // fill the middle
  817. COLORREF clr = clr3DFace;
  818. pDC->FillSolidRect(rect, clr);
  819. }
  820. void CXTSplitterWnd::OnLButtonUp(UINT nFlags, CPoint point)
  821. {
  822. CSplitterWnd::OnLButtonUp(nFlags, point);
  823. Invalidate();
  824. }
  825. void CXTSplitterWnd::SetActivePane(int row, int col, CWnd* pWnd/*= NULL*/)
  826. {
  827. // set the focus to the pane
  828. CWnd* pPane = pWnd == NULL ? GetPane(row, col) : pWnd;
  829. if (pPane->IsKindOf(RUNTIME_CLASS(CView)))
  830. {
  831. CFrameWnd* pFrameWnd = GetParentFrame();
  832. ASSERT_VALID(pFrameWnd);
  833. pFrameWnd->SetActiveView((CView*)pPane);
  834. }
  835. else
  836. {
  837. pPane->SetFocus();
  838. }
  839. }
  840. //////////////////////////////////////////////////////////////////////
  841. // CXTSplitterWndEx
  842. //
  843. IMPLEMENT_DYNAMIC(CXTSplitterWndEx, CXTSplitterWnd)
  844. BEGIN_MESSAGE_MAP(CXTSplitterWndEx, CXTSplitterWnd)
  845. //{{AFX_MSG_MAP(CXTSplitterWndEx)
  846. ON_WM_ERASEBKGND()
  847. ON_WM_PAINT()
  848. //}}AFX_MSG_MAP
  849. END_MESSAGE_MAP()
  850. CXTSplitterWndEx::CXTSplitterWndEx()
  851. {
  852. m_cxBorder = 0;
  853. m_cyBorder = 0;
  854. m_cxSplitter = 4;
  855. m_cySplitter = 4;
  856. m_cxSplitterGap = 4;
  857. m_cySplitterGap = 4;
  858. m_cyTopBorderGap = 6;
  859. m_bShowTopBorder = true;
  860. }
  861. CXTSplitterWndEx::~CXTSplitterWndEx()
  862. {
  863. }
  864. void CXTSplitterWndEx::OnDrawSplitter(CDC* pDC, ESplitType nType, const CRect& rectArg)
  865. {
  866. COLORREF clr3DFace = GetTheme()->m_clrSplitterFace;
  867. COLORREF clr3DShadow = GetTheme()->m_clrSplitterBorders;
  868. if (pDC == NULL)
  869. {
  870. RedrawWindow(rectArg, NULL, RDW_INVALIDATE | RDW_NOCHILDREN);
  871. return;
  872. }
  873. ASSERT_VALID(pDC);
  874. CRect rect = rectArg;
  875. switch (nType)
  876. {
  877. case splitBorder:
  878. return;
  879. case splitBox:
  880. pDC->Draw3dRect(rect, clr3DFace, GetXtremeColor(COLOR_WINDOWFRAME));
  881. rect.InflateRect(-CX_BORDER, -CY_BORDER);
  882. pDC->Draw3dRect(rect, GetXtremeColor(COLOR_3DHILIGHT), clr3DShadow);
  883. rect.InflateRect(-CX_BORDER, -CY_BORDER);
  884. break;
  885. }
  886. pDC->FillSolidRect(rect, clr3DFace);
  887. }
  888. // Generic routine:
  889. //  for X direction: pInfo = m_pColInfo, nMax = m_nMaxCols, nSize = cx
  890. //  for Y direction: pInfo = m_pRowInfo, nMax = m_nMaxRows, nSize = cy
  891. void CXTSplitterWndEx::LayoutRowCol(CSplitterWnd::CRowColInfo* pInfoArray,
  892. int nMax, int nSize, int nSizeSplitter)
  893. {
  894. ASSERT(pInfoArray != NULL);
  895. ASSERT(nMax > 0);
  896. ASSERT(nSizeSplitter > 0);
  897. if (!pInfoArray)
  898. return;
  899. CSplitterWnd::CRowColInfo* pInfo = NULL;
  900. int i;
  901. if (nSize < 0)
  902. nSize = 0;  // if really too small, layout as zero size
  903. // start with ideal sizes
  904. for (i = 0, pInfo = pInfoArray; i < nMax-1; i++, pInfo++)
  905. {
  906. if (pInfo->nIdealSize < pInfo->nMinSize)
  907. pInfo->nIdealSize = 0;      // too small to see
  908. pInfo->nCurSize = pInfo->nIdealSize;
  909. }
  910. if (!pInfo)
  911. return;
  912. pInfo->nCurSize = INT_MAX;  // last row/column takes the rest
  913. for (i = 0, pInfo = pInfoArray; i < nMax; i++, pInfo++)
  914. {
  915. ASSERT(nSize >= 0);
  916. if (nSize == 0)
  917. {
  918. // no more room (set pane to be invisible)
  919. pInfo->nCurSize = 0;
  920. continue;       // don't worry about splitters
  921. }
  922. else if (nSize < pInfo->nMinSize && i != 0)
  923. {
  924. // additional panes below the recommended minimum size
  925. //   aren't shown and the size goes to the previous pane
  926. pInfo->nCurSize = 0;
  927. // previous pane already has room for splitter + border
  928. //   add remaining size and remove the extra border
  929. ASSERT(CX_BORDER * 2 == CY_BORDER * 2);
  930. (pInfo-1)->nCurSize += nSize + CX_BORDER * 2;
  931. nSize = 0;
  932. }
  933. else
  934. {
  935. // otherwise we can add the second pane
  936. ASSERT(nSize > 0);
  937. if (pInfo->nCurSize == 0)
  938. {
  939. // too small to see
  940. if (i != 0)
  941. pInfo->nCurSize = 0;
  942. }
  943. else if (nSize < pInfo->nCurSize)
  944. {
  945. // this row/col won't fit completely - make as small as possible
  946. pInfo->nCurSize = nSize;
  947. nSize = 0;
  948. }
  949. else
  950. {
  951. // can fit everything
  952. nSize -= pInfo->nCurSize;
  953. }
  954. }
  955. // see if we should add a splitter
  956. ASSERT(nSize >= 0);
  957. if (i != nMax - 1)
  958. {
  959. // should have a splitter
  960. if (nSize > nSizeSplitter)
  961. {
  962. nSize -= nSizeSplitter; // leave room for splitter + border
  963. ASSERT(nSize > 0);
  964. }
  965. else
  966. {
  967. // not enough room - add left over less splitter size
  968. ASSERT(CX_BORDER * 2 == CY_BORDER * 2);
  969. pInfo->nCurSize += nSize;
  970. if (pInfo->nCurSize > (nSizeSplitter - CX_BORDER * 2))
  971. pInfo->nCurSize -= (nSizeSplitter - CY_BORDER * 2);
  972. nSize = 0;
  973. }
  974. }
  975. }
  976. ASSERT(nSize == 0); // all space should be allocated
  977. }
  978. // repositions client area of specified window
  979. // assumes everything has WS_BORDER or is inset like it does
  980. //  (includes scroll bars)
  981. void CXTSplitterWndEx::DeferClientPos(AFX_SIZEPARENTPARAMS* lpLayout,
  982. CWnd* pWnd, int x, int y, int cx, int cy, BOOL bScrollBar)
  983. {
  984. ASSERT(pWnd != NULL);
  985. if (!pWnd)
  986. return;
  987. ASSERT(pWnd->m_hWnd != NULL);
  988. if (bScrollBar)
  989. {
  990. // if there is enough room, draw scroll bar without border
  991. // if there is not enough room, set the WS_BORDER bit so that
  992. //   we will at least get a proper border drawn
  993. BOOL bNeedBorder = (cx <= CX_BORDER || cy <= CY_BORDER);
  994. pWnd->ModifyStyle(bNeedBorder ? 0 : WS_BORDER,
  995. bNeedBorder ? WS_BORDER : 0);
  996. }
  997. CRect rect(x, y, x + cx, y + cy);
  998. // adjust for border size (even if zero client size)
  999. // adjust for 3d border (splitter windows have implied border)
  1000. if ((pWnd->GetExStyle() & WS_EX_CLIENTEDGE) ||
  1001. pWnd->IsKindOf(RUNTIME_CLASS(CSplitterWnd)))
  1002. rect.InflateRect(CX_BORDER * 2, CY_BORDER * 2);
  1003. // first check if the new rectangle is the same as the current
  1004. CRect rectOld;
  1005. pWnd->GetWindowRect(rectOld);
  1006. pWnd->GetParent()->ScreenToClient(&rectOld);
  1007. if (rect != rectOld)
  1008. AfxRepositionWindow(lpLayout, pWnd->m_hWnd, rect);
  1009. }
  1010. void CXTSplitterWndEx::RecalcLayout()
  1011. {
  1012. ASSERT_VALID(this);
  1013. ASSERT(m_nRows > 0 && m_nCols > 0); // must have at least one pane
  1014. CRect rectClient;
  1015. GetClientRect(rectClient);
  1016. rectClient.InflateRect(-m_cxBorder, -m_cyBorder);
  1017. rectClient.top += m_cyTopBorderGap;
  1018. CRect rectInside;
  1019. GetInsideRect(rectInside);
  1020. // layout columns (restrict to possible sizes)
  1021. LayoutRowCol(m_pColInfo, m_nCols, rectInside.Width(), m_cxSplitterGap);
  1022. LayoutRowCol(m_pRowInfo, m_nRows, rectInside.Height(), m_cySplitterGap);
  1023. // adjust the panes (and optionally scroll bars)
  1024. // give the hint for the maximum number of HWNDs
  1025. AFX_SIZEPARENTPARAMS layout;
  1026. layout.hDWP = ::BeginDeferWindowPos((m_nCols + 1) * (m_nRows + 1) + 1);
  1027. // size of scrollbars
  1028. int cx = (rectClient.right - rectInside.right);
  1029. int cy = (rectClient.bottom - rectInside.bottom);
  1030. // reposition size box
  1031. if (m_bHasHScroll && m_bHasVScroll)
  1032. {
  1033. CWnd* pScrollBar = GetDlgItem(AFX_IDW_SIZE_BOX);
  1034. ASSERT(pScrollBar != NULL);
  1035. // fix style if necessary
  1036. BOOL bSizingParent = (GetSizingParent() != NULL);
  1037. // modifyStyle returns TRUE if style changes
  1038. if (pScrollBar->ModifyStyle(SBS_SIZEGRIP | SBS_SIZEBOX,
  1039. bSizingParent ? SBS_SIZEGRIP : SBS_SIZEBOX))
  1040. pScrollBar->Invalidate();
  1041. pScrollBar->EnableWindow(bSizingParent);
  1042. // reposition the size box
  1043. DeferClientPos(&layout, pScrollBar,
  1044. rectInside.right, rectInside.bottom, cx, cy, TRUE);
  1045. }
  1046. // reposition scroll bars
  1047. if (m_bHasHScroll)
  1048. {
  1049. int cxSplitterBox = m_cxSplitter;// split box bigger
  1050. int x = rectClient.left;
  1051. int y = rectInside.bottom;
  1052. int col;
  1053. for (col = 0; col < m_nCols; col++)
  1054. {
  1055. CWnd* pScrollBar = GetDlgItem(AFX_IDW_HSCROLL_FIRST + col);
  1056. ASSERT(pScrollBar != NULL);
  1057. int cxColumn = m_pColInfo[col].nCurSize;
  1058. if (col == 0 && m_nCols < m_nMaxCols)
  1059. x += cxSplitterBox, cxColumn -= cxSplitterBox;
  1060. DeferClientPos(&layout, pScrollBar, x, y, cxColumn, cy, TRUE);
  1061. x += cxColumn + m_cxSplitterGap;
  1062. }
  1063. }
  1064. if (m_bHasVScroll)
  1065. {
  1066. int cySplitterBox = m_cySplitter;// split box bigger
  1067. int x = rectInside.right;
  1068. int y = rectClient.top;
  1069. int row;
  1070. for (row = 0; row < m_nRows; row++)
  1071. {
  1072. CWnd* pScrollBar = GetDlgItem(AFX_IDW_VSCROLL_FIRST + row);
  1073. ASSERT(pScrollBar != NULL);
  1074. int cyColumn = m_pRowInfo[row].nCurSize;
  1075. if (row == 0 && m_nRows < m_nMaxRows)
  1076. y += cySplitterBox, cyColumn -= cySplitterBox;
  1077. DeferClientPos(&layout, pScrollBar, x, y, cx, cyColumn, TRUE);
  1078. y += cyColumn + m_cySplitterGap;
  1079. }
  1080. }
  1081. //BLOCK: Reposition all the panes
  1082. {
  1083. int x = rectClient.left;
  1084. int col;
  1085. for (col = 0; col < m_nCols; col++)
  1086. {
  1087. int cxColumn = m_pColInfo[col].nCurSize;
  1088. int y = rectClient.top;
  1089. int row;
  1090. for (row = 0; row < m_nRows; row++)
  1091. {
  1092. int cyColumn = m_pRowInfo[row].nCurSize;
  1093. CWnd* pWnd = GetPane(row, col);
  1094. DeferClientPos(&layout, pWnd, x, y, cxColumn, cyColumn, FALSE);
  1095. y += cyColumn + m_cySplitterGap;
  1096. }
  1097. x += cxColumn + m_cxSplitterGap;
  1098. }
  1099. }
  1100. // move and resize all the windows at once!
  1101. if (layout.hDWP == NULL || !::EndDeferWindowPos(layout.hDWP))
  1102. TRACE0("Warning: DeferWindowPos failed - low system resources.n");
  1103. // invalidate all the splitter bars (with NULL pDC)
  1104. DrawAllSplitBars(NULL, rectInside.right, rectInside.bottom);
  1105. }
  1106. void CXTSplitterWndEx::GetInsideRect(CRect& rect) const
  1107. {
  1108. CSplitterWnd::GetInsideRect(rect);
  1109. rect.top += m_cyTopBorderGap;
  1110. }
  1111. void CXTSplitterWndEx::OnPaint()
  1112. {
  1113. CSplitterWnd::OnPaint();
  1114. if (m_bShowTopBorder)
  1115. {
  1116. CClientDC dc(this);
  1117. int iSavedDC = dc.SaveDC();
  1118. CRect rectClient;
  1119. GetClientRect(rectClient);
  1120. if (GetTheme()->GetTheme() == xtThemeDefault)
  1121. {
  1122. CPen penShadow(PS_SOLID, 1, GetXtremeColor(COLOR_3DSHADOW));
  1123. dc.SelectObject(&penShadow);
  1124. dc.MoveTo(rectClient.left, rectClient.top);
  1125. dc.LineTo(rectClient.right, rectClient.top);
  1126. }
  1127. CPen penHilight(PS_SOLID, 1, GetXtremeColor(COLOR_3DHILIGHT));
  1128. dc.SelectObject(&penHilight);
  1129. dc.MoveTo(rectClient.left, rectClient.top + 1);
  1130. dc.LineTo(rectClient.right, rectClient.top + 1);
  1131. dc.RestoreDC(iSavedDC);
  1132. }
  1133. }
  1134. BOOL CXTSplitterWndEx::OnEraseBkgnd(CDC* pDC)
  1135. {
  1136. CRect rectClient;
  1137. GetClientRect(rectClient);
  1138. rectClient.InflateRect(-m_cxBorder, -m_cyBorder);
  1139. rectClient.bottom = rectClient.top + m_cyTopBorderGap;
  1140. COLORREF clr3DFace = GetTheme()->m_clrSplitterFace;
  1141. pDC->FillSolidRect(rectClient, clr3DFace);
  1142. return TRUE;
  1143. }