1 // Windows Template Library - WTL version 8.0
2 // Copyright (C) Microsoft Corporation. All rights reserved.
4 // This file is a part of the Windows Template Library.
5 // The use and distribution terms for this software are covered by the
6 // Microsoft Permissive License (Ms-PL) which can be found in the file
7 // Ms-PL.txt at the root of this distribution.
10 #define __ATLSPLIT_H__
15 #error ATL requires C++ compilation (use a .cpp suffix)
19 #error atlsplit.h requires atlapp.h to be included first
23 #error atlsplit.h requires atlwin.h to be included first
27 ///////////////////////////////////////////////////////////////////////////////
28 // Classes in this file:
30 // CSplitterImpl<T, t_bVertical>
31 // CSplitterWindowImpl<T, t_bVertical, TBase, TWinTraits>
32 // CSplitterWindowT<t_bVertical>
38 ///////////////////////////////////////////////////////////////////////////////
39 // CSplitterImpl - Provides splitter support to any window
41 // Splitter panes constants
42 #define SPLIT_PANE_LEFT 0
43 #define SPLIT_PANE_RIGHT 1
44 #define SPLIT_PANE_TOP SPLIT_PANE_LEFT
45 #define SPLIT_PANE_BOTTOM SPLIT_PANE_RIGHT
46 #define SPLIT_PANE_NONE -1
48 // Splitter extended styles
49 #define SPLIT_PROPORTIONAL 0x00000001
50 #define SPLIT_NONINTERACTIVE 0x00000002
51 #define SPLIT_RIGHTALIGNED 0x00000004
52 #define SPLIT_BOTTOMALIGNED SPLIT_RIGHTALIGNED
54 // Note: SPLIT_PROPORTIONAL and SPLIT_RIGHTALIGNED/SPLIT_BOTTOMALIGNED are
55 // mutually exclusive. If both are set, splitter defaults to SPLIT_PROPORTIONAL
58 template <class T, bool t_bVertical = true>
62 enum { m_nPanesCount = 2, m_nPropMax = 10000 };
64 HWND m_hWndPane[m_nPanesCount];
68 int m_cxySplitBar; // splitter bar width/height
69 static HCURSOR m_hCursor;
70 int m_cxyMin; // minimum pane size
71 int m_cxyBarEdge; // splitter bar edge
74 int m_nProportionalPos;
75 bool m_bUpdateProportionalPos;
76 DWORD m_dwExtendedStyle; // splitter specific extended styles
77 int m_nSinglePane; // single pane mode
81 m_xySplitterPos(-1), m_nDefActivePane(SPLIT_PANE_NONE),
82 m_cxySplitBar(0), m_cxyMin(0), m_cxyBarEdge(0), m_bFullDrag(true),
83 m_cxyDragOffset(0), m_nProportionalPos(0), m_bUpdateProportionalPos(true),
84 m_dwExtendedStyle(SPLIT_PROPORTIONAL),
85 m_nSinglePane(SPLIT_PANE_NONE)
87 m_hWndPane[SPLIT_PANE_LEFT] = NULL;
88 m_hWndPane[SPLIT_PANE_RIGHT] = NULL;
90 ::SetRectEmpty(&m_rcSplitter);
94 CStaticDataInitCriticalSectionLock lock;
95 if(FAILED(lock.Lock()))
97 ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CSplitterImpl::CSplitterImpl.\n"));
102 if(m_hCursor == NULL)
103 m_hCursor = ::LoadCursor(NULL, t_bVertical ? IDC_SIZEWE : IDC_SIZENS);
110 void SetSplitterRect(LPRECT lpRect = NULL, bool bUpdate = true)
114 T* pT = static_cast<T*>(this);
115 pT->GetClientRect(&m_rcSplitter);
119 m_rcSplitter = *lpRect;
123 UpdateProportionalPos();
124 else if(IsRightAligned())
125 UpdateRightAlignPos();
128 UpdateSplitterLayout();
131 void GetSplitterRect(LPRECT lpRect) const
133 ATLASSERT(lpRect != NULL);
134 *lpRect = m_rcSplitter;
137 bool SetSplitterPos(int xyPos = -1, bool bUpdate = true)
139 if(xyPos == -1) // -1 == middle
142 xyPos = (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) / 2;
144 xyPos = (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge) / 2;
147 // Adjust if out of valid range
150 cxyMax = m_rcSplitter.right - m_rcSplitter.left;
152 cxyMax = m_rcSplitter.bottom - m_rcSplitter.top;
154 if(xyPos < m_cxyMin + m_cxyBarEdge)
156 else if(xyPos > (cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin))
157 xyPos = cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin;
159 // Set new position and update if requested
160 bool bRet = (m_xySplitterPos != xyPos);
161 m_xySplitterPos = xyPos;
163 if(m_bUpdateProportionalPos)
166 StoreProportionalPos();
167 else if(IsRightAligned())
168 StoreRightAlignPos();
172 m_bUpdateProportionalPos = true;
176 UpdateSplitterLayout();
181 void SetSplitterPosPct(int nPct, bool bUpdate = true)
183 ATLASSERT(nPct >= 0 && nPct <= 100);
185 m_nProportionalPos = ::MulDiv(nPct, m_nPropMax, 100);
186 UpdateProportionalPos();
189 UpdateSplitterLayout();
192 int GetSplitterPos() const
194 return m_xySplitterPos;
197 bool SetSinglePaneMode(int nPane = SPLIT_PANE_NONE)
199 ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT || nPane == SPLIT_PANE_NONE);
200 if(!(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT || nPane == SPLIT_PANE_NONE))
203 if(nPane != SPLIT_PANE_NONE)
205 if(!::IsWindowVisible(m_hWndPane[nPane]))
206 ::ShowWindow(m_hWndPane[nPane], SW_SHOW);
207 int nOtherPane = (nPane == SPLIT_PANE_LEFT) ? SPLIT_PANE_RIGHT : SPLIT_PANE_LEFT;
208 ::ShowWindow(m_hWndPane[nOtherPane], SW_HIDE);
209 if(m_nDefActivePane != nPane)
210 m_nDefActivePane = nPane;
212 else if(m_nSinglePane != SPLIT_PANE_NONE)
214 int nOtherPane = (m_nSinglePane == SPLIT_PANE_LEFT) ? SPLIT_PANE_RIGHT : SPLIT_PANE_LEFT;
215 ::ShowWindow(m_hWndPane[nOtherPane], SW_SHOW);
218 m_nSinglePane = nPane;
219 UpdateSplitterLayout();
223 int GetSinglePaneMode() const
225 return m_nSinglePane;
228 DWORD GetSplitterExtendedStyle() const
230 return m_dwExtendedStyle;
233 DWORD SetSplitterExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)
235 DWORD dwPrevStyle = m_dwExtendedStyle;
237 m_dwExtendedStyle = dwExtendedStyle;
239 m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);
241 if(IsProportional() && IsRightAligned())
242 ATLTRACE2(atlTraceUI, 0, _T("CSplitterImpl::SetSplitterExtendedStyle - SPLIT_PROPORTIONAL and SPLIT_RIGHTALIGNED are mutually exclusive, defaulting to SPLIT_PROPORTIONAL.\n"));
247 // Splitter operations
248 void SetSplitterPanes(HWND hWndLeftTop, HWND hWndRightBottom, bool bUpdate = true)
250 m_hWndPane[SPLIT_PANE_LEFT] = hWndLeftTop;
251 m_hWndPane[SPLIT_PANE_RIGHT] = hWndRightBottom;
252 ATLASSERT(m_hWndPane[SPLIT_PANE_LEFT] == NULL || m_hWndPane[SPLIT_PANE_RIGHT] == NULL || m_hWndPane[SPLIT_PANE_LEFT] != m_hWndPane[SPLIT_PANE_RIGHT]);
254 UpdateSplitterLayout();
257 bool SetSplitterPane(int nPane, HWND hWnd, bool bUpdate = true)
259 ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT);
261 if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT)
263 m_hWndPane[nPane] = hWnd;
264 ATLASSERT(m_hWndPane[SPLIT_PANE_LEFT] == NULL || m_hWndPane[SPLIT_PANE_RIGHT] == NULL || m_hWndPane[SPLIT_PANE_LEFT] != m_hWndPane[SPLIT_PANE_RIGHT]);
266 UpdateSplitterLayout();
270 HWND GetSplitterPane(int nPane) const
272 ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT);
274 if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT)
276 return m_hWndPane[nPane];
279 bool SetActivePane(int nPane)
281 ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT);
283 if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT)
285 if(m_nSinglePane != SPLIT_PANE_NONE && nPane != m_nSinglePane)
287 ::SetFocus(m_hWndPane[nPane]);
288 m_nDefActivePane = nPane;
292 int GetActivePane() const
294 int nRet = SPLIT_PANE_NONE;
295 HWND hWndFocus = ::GetFocus();
296 if(hWndFocus != NULL)
298 for(int nPane = 0; nPane < m_nPanesCount; nPane++)
300 if(hWndFocus == m_hWndPane[nPane] || ::IsChild(m_hWndPane[nPane], hWndFocus))
310 bool ActivateNextPane(bool bNext = true)
312 int nPane = m_nSinglePane;
313 if(nPane == SPLIT_PANE_NONE)
315 switch(GetActivePane())
317 case SPLIT_PANE_LEFT:
318 nPane = SPLIT_PANE_RIGHT;
320 case SPLIT_PANE_RIGHT:
321 nPane = SPLIT_PANE_LEFT;
324 nPane = bNext ? SPLIT_PANE_LEFT : SPLIT_PANE_RIGHT;
328 return SetActivePane(nPane);
331 bool SetDefaultActivePane(int nPane)
333 ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT);
335 if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT)
337 m_nDefActivePane = nPane;
341 bool SetDefaultActivePane(HWND hWnd)
343 for(int nPane = 0; nPane < m_nPanesCount; nPane++)
345 if(hWnd == m_hWndPane[nPane])
347 m_nDefActivePane = nPane;
351 return false; // not found
354 int GetDefaultActivePane() const
356 return m_nDefActivePane;
359 void DrawSplitter(CDCHandle dc)
361 ATLASSERT(dc.m_hDC != NULL);
362 if(m_nSinglePane == SPLIT_PANE_NONE && m_xySplitterPos == -1)
365 T* pT = static_cast<T*>(this);
366 if(m_nSinglePane == SPLIT_PANE_NONE)
368 pT->DrawSplitterBar(dc);
370 for(int nPane = 0; nPane < m_nPanesCount; nPane++)
372 if(m_hWndPane[nPane] == NULL)
373 pT->DrawSplitterPane(dc, nPane);
378 if(m_hWndPane[m_nSinglePane] == NULL)
379 pT->DrawSplitterPane(dc, m_nSinglePane);
384 void DrawSplitterBar(CDCHandle dc)
387 if(GetSplitterBarRect(&rect))
389 dc.FillRect(&rect, COLOR_3DFACE);
390 // draw 3D edge if needed
391 T* pT = static_cast<T*>(this);
392 if((pT->GetExStyle() & WS_EX_CLIENTEDGE) != 0)
393 dc.DrawEdge(&rect, EDGE_RAISED, t_bVertical ? (BF_LEFT | BF_RIGHT) : (BF_TOP | BF_BOTTOM));
397 // called only if pane is empty
398 void DrawSplitterPane(CDCHandle dc, int nPane)
401 if(GetSplitterPaneRect(nPane, &rect))
403 T* pT = static_cast<T*>(this);
404 if((pT->GetExStyle() & WS_EX_CLIENTEDGE) == 0)
405 dc.DrawEdge(&rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
406 dc.FillRect(&rect, COLOR_APPWORKSPACE);
410 // Message map and handlers
411 BEGIN_MSG_MAP(CSplitterImpl)
412 MESSAGE_HANDLER(WM_CREATE, OnCreate)
413 MESSAGE_HANDLER(WM_PAINT, OnPaint)
415 MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
416 #endif // !_WIN32_WCE
419 MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor)
420 MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
421 MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
422 MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
423 MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDoubleClick)
424 MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged)
426 MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
428 MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate)
429 #endif // !_WIN32_WCE
430 MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)
433 LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
435 GetSystemSettings(false);
440 LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
442 T* pT = static_cast<T*>(this);
443 // try setting position if not set
444 if(m_nSinglePane == SPLIT_PANE_NONE && m_xySplitterPos == -1)
445 pT->SetSplitterPos();
447 CPaintDC dc(pT->m_hWnd);
448 pT->DrawSplitter(dc.m_hDC);
452 LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
454 T* pT = static_cast<T*>(this);
455 if((HWND)wParam == pT->m_hWnd && LOWORD(lParam) == HTCLIENT)
457 DWORD dwPos = ::GetMessagePos();
458 POINT ptPos = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) };
459 pT->ScreenToClient(&ptPos);
460 if(IsOverSplitterBar(ptPos.x, ptPos.y))
468 LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
470 T* pT = static_cast<T*>(this);
471 int xPos = GET_X_LPARAM(lParam);
472 int yPos = GET_Y_LPARAM(lParam);
473 if((wParam & MK_LBUTTON) && ::GetCapture() == pT->m_hWnd)
475 int xyNewSplitPos = 0;
477 xyNewSplitPos = xPos - m_rcSplitter.left - m_cxyDragOffset;
479 xyNewSplitPos = yPos - m_rcSplitter.top - m_cxyDragOffset;
481 if(xyNewSplitPos == -1) // avoid -1, that means middle
484 if(m_xySplitterPos != xyNewSplitPos)
488 if(pT->SetSplitterPos(xyNewSplitPos, true))
494 pT->SetSplitterPos(xyNewSplitPos, false);
499 else // not dragging, just set cursor
501 if(IsOverSplitterBar(xPos, yPos))
502 ::SetCursor(m_hCursor);
509 LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
511 int xPos = GET_X_LPARAM(lParam);
512 int yPos = GET_Y_LPARAM(lParam);
513 if(IsOverSplitterBar(xPos, yPos))
515 T* pT = static_cast<T*>(this);
517 ::SetCursor(m_hCursor);
521 m_cxyDragOffset = xPos - m_rcSplitter.left - m_xySplitterPos;
523 m_cxyDragOffset = yPos - m_rcSplitter.top - m_xySplitterPos;
529 LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
536 LRESULT OnLButtonDoubleClick(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
538 T* pT = static_cast<T*>(this);
539 pT->SetSplitterPos(); // middle
543 LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
548 UpdateSplitterLayout();
549 T* pT = static_cast<T*>(this);
555 LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM, BOOL& bHandled)
557 if(m_nSinglePane == SPLIT_PANE_NONE)
559 if(m_nDefActivePane == SPLIT_PANE_LEFT || m_nDefActivePane == SPLIT_PANE_RIGHT)
560 ::SetFocus(m_hWndPane[m_nDefActivePane]);
564 ::SetFocus(m_hWndPane[m_nSinglePane]);
571 LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
573 T* pT = static_cast<T*>(this);
574 LRESULT lRet = pT->DefWindowProc(uMsg, wParam, lParam);
575 if(lRet == MA_ACTIVATE || lRet == MA_ACTIVATEANDEAT)
577 DWORD dwPos = ::GetMessagePos();
578 POINT pt = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) };
579 pT->ScreenToClient(&pt);
581 for(int nPane = 0; nPane < m_nPanesCount; nPane++)
583 if(GetSplitterPaneRect(nPane, &rcPane) && ::PtInRect(&rcPane, pt))
585 m_nDefActivePane = nPane;
592 #endif // !_WIN32_WCE
594 LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
596 GetSystemSettings(true);
600 // Implementation - internal helpers
601 void UpdateSplitterLayout()
603 if(m_nSinglePane == SPLIT_PANE_NONE && m_xySplitterPos == -1)
606 T* pT = static_cast<T*>(this);
607 RECT rect = { 0, 0, 0, 0 };
608 if(m_nSinglePane == SPLIT_PANE_NONE)
610 if(GetSplitterBarRect(&rect))
611 pT->InvalidateRect(&rect);
613 for(int nPane = 0; nPane < m_nPanesCount; nPane++)
615 if(GetSplitterPaneRect(nPane, &rect))
617 if(m_hWndPane[nPane] != NULL)
618 ::SetWindowPos(m_hWndPane[nPane], NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
620 pT->InvalidateRect(&rect);
626 if(GetSplitterPaneRect(m_nSinglePane, &rect))
628 if(m_hWndPane[m_nSinglePane] != NULL)
629 ::SetWindowPos(m_hWndPane[m_nSinglePane], NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
631 pT->InvalidateRect(&rect);
636 bool GetSplitterBarRect(LPRECT lpRect) const
638 ATLASSERT(lpRect != NULL);
639 if(m_nSinglePane != SPLIT_PANE_NONE || m_xySplitterPos == -1)
644 lpRect->left = m_rcSplitter.left + m_xySplitterPos;
645 lpRect->top = m_rcSplitter.top;
646 lpRect->right = m_rcSplitter.left + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge;
647 lpRect->bottom = m_rcSplitter.bottom;
651 lpRect->left = m_rcSplitter.left;
652 lpRect->top = m_rcSplitter.top + m_xySplitterPos;
653 lpRect->right = m_rcSplitter.right;
654 lpRect->bottom = m_rcSplitter.top + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge;
660 bool GetSplitterPaneRect(int nPane, LPRECT lpRect) const
662 ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT);
663 ATLASSERT(lpRect != NULL);
665 if(m_nSinglePane != SPLIT_PANE_NONE)
667 if(nPane == m_nSinglePane)
668 *lpRect = m_rcSplitter;
672 else if(nPane == SPLIT_PANE_LEFT)
676 lpRect->left = m_rcSplitter.left;
677 lpRect->top = m_rcSplitter.top;
678 lpRect->right = m_rcSplitter.left + m_xySplitterPos;
679 lpRect->bottom = m_rcSplitter.bottom;
683 lpRect->left = m_rcSplitter.left;
684 lpRect->top = m_rcSplitter.top;
685 lpRect->right = m_rcSplitter.right;
686 lpRect->bottom = m_rcSplitter.top + m_xySplitterPos;
689 else if(nPane == SPLIT_PANE_RIGHT)
693 lpRect->left = m_rcSplitter.left + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge;
694 lpRect->top = m_rcSplitter.top;
695 lpRect->right = m_rcSplitter.right;
696 lpRect->bottom = m_rcSplitter.bottom;
700 lpRect->left = m_rcSplitter.left;
701 lpRect->top = m_rcSplitter.top + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge;
702 lpRect->right = m_rcSplitter.right;
703 lpRect->bottom = m_rcSplitter.bottom;
713 bool IsOverSplitterRect(int x, int y) const
716 return ((x == -1 || (x >= m_rcSplitter.left && x <= m_rcSplitter.right)) &&
717 (y == -1 || (y >= m_rcSplitter.top && y <= m_rcSplitter.bottom)));
720 bool IsOverSplitterBar(int x, int y) const
722 if(m_nSinglePane != SPLIT_PANE_NONE)
724 if(m_xySplitterPos == -1 || !IsOverSplitterRect(x, y))
726 int xy = t_bVertical ? x : y;
727 int xyOff = t_bVertical ? m_rcSplitter.left : m_rcSplitter.top;
728 return ((xy >= (xyOff + m_xySplitterPos)) && (xy < xyOff + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge));
733 RECT rect = { 0, 0, 0, 0 };
734 if(GetSplitterBarRect(&rect))
736 // invert the brush pattern (looks just like frame window sizing)
737 T* pT = static_cast<T*>(this);
738 CWindowDC dc(pT->m_hWnd);
739 CBrush brush = CDCHandle::GetHalftoneBrush();
740 if(brush.m_hBrush != NULL)
742 CBrushHandle brushOld = dc.SelectBrush(brush);
743 dc.PatBlt(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, PATINVERT);
744 dc.SelectBrush(brushOld);
749 void GetSystemSettings(bool bUpdate)
752 m_cxySplitBar = ::GetSystemMetrics(t_bVertical ? SM_CXSIZEFRAME : SM_CYSIZEFRAME);
754 m_cxySplitBar = 2 * ::GetSystemMetrics(t_bVertical ? SM_CXEDGE : SM_CYEDGE);
757 T* pT = static_cast<T*>(this);
758 if((pT->GetExStyle() & WS_EX_CLIENTEDGE))
760 m_cxyBarEdge = 2 * ::GetSystemMetrics(t_bVertical ? SM_CXEDGE : SM_CYEDGE);
766 m_cxyMin = 2 * ::GetSystemMetrics(t_bVertical ? SM_CXEDGE : SM_CYEDGE);
770 ::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &m_bFullDrag, 0);
771 #endif // !_WIN32_WCE
774 UpdateSplitterLayout();
777 bool IsProportional() const
779 return ((m_dwExtendedStyle & SPLIT_PROPORTIONAL) != 0);
782 void StoreProportionalPos()
784 int cxyTotal = t_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge);
786 m_nProportionalPos = ::MulDiv(m_xySplitterPos, m_nPropMax, cxyTotal);
788 m_nProportionalPos = 0;
789 ATLTRACE2(atlTraceUI, 0, _T("CSplitterImpl::StoreProportionalPos - %i\n"), m_nProportionalPos);
792 void UpdateProportionalPos()
794 int cxyTotal = t_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge);
797 int xyNewPos = ::MulDiv(m_nProportionalPos, cxyTotal, m_nPropMax);
798 m_bUpdateProportionalPos = false;
799 T* pT = static_cast<T*>(this);
800 pT->SetSplitterPos(xyNewPos, false);
804 bool IsRightAligned() const
806 return ((m_dwExtendedStyle & SPLIT_RIGHTALIGNED) != 0);
809 void StoreRightAlignPos()
811 int cxyTotal = t_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge);
813 m_nProportionalPos = cxyTotal - m_xySplitterPos;
815 m_nProportionalPos = 0;
816 ATLTRACE2(atlTraceUI, 0, _T("CSplitterImpl::StoreRightAlignPos - %i\n"), m_nProportionalPos);
819 void UpdateRightAlignPos()
821 int cxyTotal = t_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge);
824 m_bUpdateProportionalPos = false;
825 T* pT = static_cast<T*>(this);
826 pT->SetSplitterPos(cxyTotal - m_nProportionalPos, false);
830 bool IsInteractive() const
832 return ((m_dwExtendedStyle & SPLIT_NONINTERACTIVE) == 0);
836 template <class T, bool t_bVertical> HCURSOR CSplitterImpl< T, t_bVertical>::m_hCursor = NULL;
839 ///////////////////////////////////////////////////////////////////////////////
840 // CSplitterWindowImpl - Implements a splitter window
842 template <class T, bool t_bVertical = true, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
843 class ATL_NO_VTABLE CSplitterWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CSplitterImpl< T , t_bVertical >
846 DECLARE_WND_CLASS_EX(NULL, CS_DBLCLKS, COLOR_WINDOW)
848 typedef CSplitterImpl< T , t_bVertical > _baseClass;
850 BEGIN_MSG_MAP(CSplitterWindowImpl)
851 MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
852 MESSAGE_HANDLER(WM_SIZE, OnSize)
853 CHAIN_MSG_MAP(_baseClass)
854 FORWARD_NOTIFICATIONS()
857 LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
859 // handled, no background painting needed
863 LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
865 if(wParam != SIZE_MINIMIZED)
874 ///////////////////////////////////////////////////////////////////////////////
875 // CSplitterWindow - Implements a splitter window to be used as is
877 template <bool t_bVertical = true>
878 class CSplitterWindowT : public CSplitterWindowImpl<CSplitterWindowT<t_bVertical>, t_bVertical>
881 DECLARE_WND_CLASS_EX(_T("WTL_SplitterWindow"), CS_DBLCLKS, COLOR_WINDOW)
884 typedef CSplitterWindowT<true> CSplitterWindow;
885 typedef CSplitterWindowT<false> CHorSplitterWindow;
889 #endif // __ATLSPLIT_H__