1 // Windows Template Library - WTL version 8.0
\r
2 // Copyright (C) Microsoft Corporation. All rights reserved.
\r
4 // This file is a part of the Windows Template Library.
\r
5 // The use and distribution terms for this software are covered by the
\r
6 // Common Public License 1.0 (http://opensource.org/osi3.0/licenses/cpl1.0.php)
\r
7 // which can be found in the file CPL.TXT at the root of this distribution.
\r
8 // By using this software in any fashion, you are agreeing to be bound by
\r
9 // the terms of this license. You must not remove this notice, or
\r
10 // any other, from this software.
\r
12 #ifndef __ATLSPLIT_H__
\r
13 #define __ATLSPLIT_H__
\r
18 #error ATL requires C++ compilation (use a .cpp suffix)
\r
21 #ifndef __ATLAPP_H__
\r
22 #error atlsplit.h requires atlapp.h to be included first
\r
25 #ifndef __ATLWIN_H__
\r
26 #error atlsplit.h requires atlwin.h to be included first
\r
30 ///////////////////////////////////////////////////////////////////////////////
\r
31 // Classes in this file:
\r
33 // CSplitterImpl<T, t_bVertical>
\r
34 // CSplitterWindowImpl<T, t_bVertical, TBase, TWinTraits>
\r
35 // CSplitterWindowT<t_bVertical>
\r
41 ///////////////////////////////////////////////////////////////////////////////
\r
42 // CSplitterImpl - Provides splitter support to any window
\r
44 // Splitter panes constants
\r
45 #define SPLIT_PANE_LEFT 0
\r
46 #define SPLIT_PANE_RIGHT 1
\r
47 #define SPLIT_PANE_TOP SPLIT_PANE_LEFT
\r
48 #define SPLIT_PANE_BOTTOM SPLIT_PANE_RIGHT
\r
49 #define SPLIT_PANE_NONE -1
\r
51 // Splitter extended styles
\r
52 #define SPLIT_PROPORTIONAL 0x00000001
\r
53 #define SPLIT_NONINTERACTIVE 0x00000002
\r
54 #define SPLIT_RIGHTALIGNED 0x00000004
\r
55 #define SPLIT_BOTTOMALIGNED SPLIT_RIGHTALIGNED
\r
57 // Note: SPLIT_PROPORTIONAL and SPLIT_RIGHTALIGNED/SPLIT_BOTTOMALIGNED are
\r
58 // mutually exclusive. If both are set, splitter defaults to SPLIT_PROPORTIONAL
\r
61 template <class T, bool t_bVertical = true>
\r
65 enum { m_nPanesCount = 2, m_nPropMax = 10000 };
\r
67 HWND m_hWndPane[m_nPanesCount];
\r
69 int m_xySplitterPos;
\r
70 int m_nDefActivePane;
\r
71 int m_cxySplitBar; // splitter bar width/height
\r
72 static HCURSOR m_hCursor;
\r
73 int m_cxyMin; // minimum pane size
\r
74 int m_cxyBarEdge; // splitter bar edge
\r
76 int m_cxyDragOffset;
\r
77 int m_nProportionalPos;
\r
78 bool m_bUpdateProportionalPos;
\r
79 DWORD m_dwExtendedStyle; // splitter specific extended styles
\r
80 int m_nSinglePane; // single pane mode
\r
84 m_xySplitterPos(-1), m_nDefActivePane(SPLIT_PANE_NONE),
\r
85 m_cxySplitBar(0), m_cxyMin(0), m_cxyBarEdge(0), m_bFullDrag(true),
\r
86 m_cxyDragOffset(0), m_nProportionalPos(0), m_bUpdateProportionalPos(true),
\r
87 m_dwExtendedStyle(SPLIT_PROPORTIONAL),
\r
88 m_nSinglePane(SPLIT_PANE_NONE)
\r
90 m_hWndPane[SPLIT_PANE_LEFT] = NULL;
\r
91 m_hWndPane[SPLIT_PANE_RIGHT] = NULL;
\r
93 ::SetRectEmpty(&m_rcSplitter);
\r
95 if(m_hCursor == NULL)
\r
97 CStaticDataInitCriticalSectionLock lock;
\r
98 if(FAILED(lock.Lock()))
\r
100 ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CSplitterImpl::CSplitterImpl.\n"));
\r
105 if(m_hCursor == NULL)
\r
106 m_hCursor = ::LoadCursor(NULL, t_bVertical ? IDC_SIZEWE : IDC_SIZENS);
\r
113 void SetSplitterRect(LPRECT lpRect = NULL, bool bUpdate = true)
\r
117 T* pT = static_cast<T*>(this);
\r
118 pT->GetClientRect(&m_rcSplitter);
\r
122 m_rcSplitter = *lpRect;
\r
125 if(IsProportional())
\r
126 UpdateProportionalPos();
\r
127 else if(IsRightAligned())
\r
128 UpdateRightAlignPos();
\r
131 UpdateSplitterLayout();
\r
134 void GetSplitterRect(LPRECT lpRect) const
\r
136 ATLASSERT(lpRect != NULL);
\r
137 *lpRect = m_rcSplitter;
\r
140 bool SetSplitterPos(int xyPos = -1, bool bUpdate = true)
\r
142 if(xyPos == -1) // -1 == middle
\r
145 xyPos = (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) / 2;
\r
147 xyPos = (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge) / 2;
\r
150 // Adjust if out of valid range
\r
153 cxyMax = m_rcSplitter.right - m_rcSplitter.left;
\r
155 cxyMax = m_rcSplitter.bottom - m_rcSplitter.top;
\r
157 if(xyPos < m_cxyMin + m_cxyBarEdge)
\r
159 else if(xyPos > (cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin))
\r
160 xyPos = cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin;
\r
162 // Set new position and update if requested
\r
163 bool bRet = (m_xySplitterPos != xyPos);
\r
164 m_xySplitterPos = xyPos;
\r
166 if(m_bUpdateProportionalPos)
\r
168 if(IsProportional())
\r
169 StoreProportionalPos();
\r
170 else if(IsRightAligned())
\r
171 StoreRightAlignPos();
\r
175 m_bUpdateProportionalPos = true;
\r
178 if(bUpdate && bRet)
\r
179 UpdateSplitterLayout();
\r
184 void SetSplitterPosPct(int nPct, bool bUpdate = true)
\r
186 ATLASSERT(nPct >= 0 && nPct <= 100);
\r
188 m_nProportionalPos = ::MulDiv(nPct, m_nPropMax, 100);
\r
189 UpdateProportionalPos();
\r
192 UpdateSplitterLayout();
\r
195 int GetSplitterPos() const
\r
197 return m_xySplitterPos;
\r
200 bool SetSinglePaneMode(int nPane = SPLIT_PANE_NONE)
\r
202 ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT || nPane == SPLIT_PANE_NONE);
\r
203 if(!(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT || nPane == SPLIT_PANE_NONE))
\r
206 if(nPane != SPLIT_PANE_NONE)
\r
208 if(!::IsWindowVisible(m_hWndPane[nPane]))
\r
209 ::ShowWindow(m_hWndPane[nPane], SW_SHOW);
\r
210 int nOtherPane = (nPane == SPLIT_PANE_LEFT) ? SPLIT_PANE_RIGHT : SPLIT_PANE_LEFT;
\r
211 ::ShowWindow(m_hWndPane[nOtherPane], SW_HIDE);
\r
212 if(m_nDefActivePane != nPane)
\r
213 m_nDefActivePane = nPane;
\r
215 else if(m_nSinglePane != SPLIT_PANE_NONE)
\r
217 int nOtherPane = (m_nSinglePane == SPLIT_PANE_LEFT) ? SPLIT_PANE_RIGHT : SPLIT_PANE_LEFT;
\r
218 ::ShowWindow(m_hWndPane[nOtherPane], SW_SHOW);
\r
221 m_nSinglePane = nPane;
\r
222 UpdateSplitterLayout();
\r
226 int GetSinglePaneMode() const
\r
228 return m_nSinglePane;
\r
231 DWORD GetSplitterExtendedStyle() const
\r
233 return m_dwExtendedStyle;
\r
236 DWORD SetSplitterExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)
\r
238 DWORD dwPrevStyle = m_dwExtendedStyle;
\r
240 m_dwExtendedStyle = dwExtendedStyle;
\r
242 m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);
\r
244 if(IsProportional() && IsRightAligned())
\r
245 ATLTRACE2(atlTraceUI, 0, _T("CSplitterImpl::SetSplitterExtendedStyle - SPLIT_PROPORTIONAL and SPLIT_RIGHTALIGNED are mutually exclusive, defaulting to SPLIT_PROPORTIONAL.\n"));
\r
247 return dwPrevStyle;
\r
250 // Splitter operations
\r
251 void SetSplitterPanes(HWND hWndLeftTop, HWND hWndRightBottom, bool bUpdate = true)
\r
253 m_hWndPane[SPLIT_PANE_LEFT] = hWndLeftTop;
\r
254 m_hWndPane[SPLIT_PANE_RIGHT] = hWndRightBottom;
\r
255 ATLASSERT(m_hWndPane[SPLIT_PANE_LEFT] == NULL || m_hWndPane[SPLIT_PANE_RIGHT] == NULL || m_hWndPane[SPLIT_PANE_LEFT] != m_hWndPane[SPLIT_PANE_RIGHT]);
\r
257 UpdateSplitterLayout();
\r
260 bool SetSplitterPane(int nPane, HWND hWnd, bool bUpdate = true)
\r
262 ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT);
\r
264 if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT)
\r
266 m_hWndPane[nPane] = hWnd;
\r
267 ATLASSERT(m_hWndPane[SPLIT_PANE_LEFT] == NULL || m_hWndPane[SPLIT_PANE_RIGHT] == NULL || m_hWndPane[SPLIT_PANE_LEFT] != m_hWndPane[SPLIT_PANE_RIGHT]);
\r
269 UpdateSplitterLayout();
\r
273 HWND GetSplitterPane(int nPane) const
\r
275 ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT);
\r
277 if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT)
\r
279 return m_hWndPane[nPane];
\r
282 bool SetActivePane(int nPane)
\r
284 ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT);
\r
286 if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT)
\r
288 if(m_nSinglePane != SPLIT_PANE_NONE && nPane != m_nSinglePane)
\r
290 ::SetFocus(m_hWndPane[nPane]);
\r
291 m_nDefActivePane = nPane;
\r
295 int GetActivePane() const
\r
297 int nRet = SPLIT_PANE_NONE;
\r
298 HWND hWndFocus = ::GetFocus();
\r
299 if(hWndFocus != NULL)
\r
301 for(int nPane = 0; nPane < m_nPanesCount; nPane++)
\r
303 if(hWndFocus == m_hWndPane[nPane] || ::IsChild(m_hWndPane[nPane], hWndFocus))
\r
313 bool ActivateNextPane(bool bNext = true)
\r
315 int nPane = m_nSinglePane;
\r
316 if(nPane == SPLIT_PANE_NONE)
\r
318 switch(GetActivePane())
\r
320 case SPLIT_PANE_LEFT:
\r
321 nPane = SPLIT_PANE_RIGHT;
\r
323 case SPLIT_PANE_RIGHT:
\r
324 nPane = SPLIT_PANE_LEFT;
\r
327 nPane = bNext ? SPLIT_PANE_LEFT : SPLIT_PANE_RIGHT;
\r
331 return SetActivePane(nPane);
\r
334 bool SetDefaultActivePane(int nPane)
\r
336 ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT);
\r
338 if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT)
\r
340 m_nDefActivePane = nPane;
\r
344 bool SetDefaultActivePane(HWND hWnd)
\r
346 for(int nPane = 0; nPane < m_nPanesCount; nPane++)
\r
348 if(hWnd == m_hWndPane[nPane])
\r
350 m_nDefActivePane = nPane;
\r
354 return false; // not found
\r
357 int GetDefaultActivePane() const
\r
359 return m_nDefActivePane;
\r
362 void DrawSplitter(CDCHandle dc)
\r
364 ATLASSERT(dc.m_hDC != NULL);
\r
365 if(m_nSinglePane == SPLIT_PANE_NONE && m_xySplitterPos == -1)
\r
368 T* pT = static_cast<T*>(this);
\r
369 if(m_nSinglePane == SPLIT_PANE_NONE)
\r
371 pT->DrawSplitterBar(dc);
\r
373 for(int nPane = 0; nPane < m_nPanesCount; nPane++)
\r
375 if(m_hWndPane[nPane] == NULL)
\r
376 pT->DrawSplitterPane(dc, nPane);
\r
381 if(m_hWndPane[m_nSinglePane] == NULL)
\r
382 pT->DrawSplitterPane(dc, m_nSinglePane);
\r
387 void DrawSplitterBar(CDCHandle dc)
\r
390 if(GetSplitterBarRect(&rect))
\r
392 dc.FillRect(&rect, COLOR_3DFACE);
\r
393 // draw 3D edge if needed
\r
394 T* pT = static_cast<T*>(this);
\r
395 if((pT->GetExStyle() & WS_EX_CLIENTEDGE) != 0)
\r
396 dc.DrawEdge(&rect, EDGE_RAISED, t_bVertical ? (BF_LEFT | BF_RIGHT) : (BF_TOP | BF_BOTTOM));
\r
400 // called only if pane is empty
\r
401 void DrawSplitterPane(CDCHandle dc, int nPane)
\r
404 if(GetSplitterPaneRect(nPane, &rect))
\r
406 T* pT = static_cast<T*>(this);
\r
407 if((pT->GetExStyle() & WS_EX_CLIENTEDGE) == 0)
\r
408 dc.DrawEdge(&rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
\r
409 dc.FillRect(&rect, COLOR_APPWORKSPACE);
\r
413 // Message map and handlers
\r
414 BEGIN_MSG_MAP(CSplitterImpl)
\r
415 MESSAGE_HANDLER(WM_CREATE, OnCreate)
\r
416 MESSAGE_HANDLER(WM_PAINT, OnPaint)
\r
418 MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
\r
419 #endif // !_WIN32_WCE
\r
420 if(IsInteractive())
\r
422 MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor)
\r
423 MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
\r
424 MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
\r
425 MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
\r
426 MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDoubleClick)
\r
427 MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged)
\r
429 MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
\r
431 MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate)
\r
432 #endif // !_WIN32_WCE
\r
433 MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)
\r
436 LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
\r
438 GetSystemSettings(false);
\r
443 LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
\r
445 T* pT = static_cast<T*>(this);
\r
446 // try setting position if not set
\r
447 if(m_nSinglePane == SPLIT_PANE_NONE && m_xySplitterPos == -1)
\r
448 pT->SetSplitterPos();
\r
450 CPaintDC dc(pT->m_hWnd);
\r
451 pT->DrawSplitter(dc.m_hDC);
\r
455 LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
\r
457 T* pT = static_cast<T*>(this);
\r
458 if((HWND)wParam == pT->m_hWnd && LOWORD(lParam) == HTCLIENT)
\r
460 DWORD dwPos = ::GetMessagePos();
\r
461 POINT ptPos = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) };
\r
462 pT->ScreenToClient(&ptPos);
\r
463 if(IsOverSplitterBar(ptPos.x, ptPos.y))
\r
471 LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
\r
473 T* pT = static_cast<T*>(this);
\r
474 int xPos = GET_X_LPARAM(lParam);
\r
475 int yPos = GET_Y_LPARAM(lParam);
\r
476 if((wParam & MK_LBUTTON) && ::GetCapture() == pT->m_hWnd)
\r
478 int xyNewSplitPos = 0;
\r
480 xyNewSplitPos = xPos - m_rcSplitter.left - m_cxyDragOffset;
\r
482 xyNewSplitPos = yPos - m_rcSplitter.top - m_cxyDragOffset;
\r
484 if(xyNewSplitPos == -1) // avoid -1, that means middle
\r
485 xyNewSplitPos = -2;
\r
487 if(m_xySplitterPos != xyNewSplitPos)
\r
491 if(pT->SetSplitterPos(xyNewSplitPos, true))
\r
492 pT->UpdateWindow();
\r
497 pT->SetSplitterPos(xyNewSplitPos, false);
\r
502 else // not dragging, just set cursor
\r
504 if(IsOverSplitterBar(xPos, yPos))
\r
505 ::SetCursor(m_hCursor);
\r
512 LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
\r
514 int xPos = GET_X_LPARAM(lParam);
\r
515 int yPos = GET_Y_LPARAM(lParam);
\r
516 if(IsOverSplitterBar(xPos, yPos))
\r
518 T* pT = static_cast<T*>(this);
\r
520 ::SetCursor(m_hCursor);
\r
524 m_cxyDragOffset = xPos - m_rcSplitter.left - m_xySplitterPos;
\r
526 m_cxyDragOffset = yPos - m_rcSplitter.top - m_xySplitterPos;
\r
532 LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
\r
534 ::ReleaseCapture();
\r
539 LRESULT OnLButtonDoubleClick(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
\r
541 T* pT = static_cast<T*>(this);
\r
542 pT->SetSplitterPos(); // middle
\r
546 LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
\r
551 UpdateSplitterLayout();
\r
552 T* pT = static_cast<T*>(this);
\r
553 pT->UpdateWindow();
\r
558 LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM, BOOL& bHandled)
\r
560 if(m_nSinglePane == SPLIT_PANE_NONE)
\r
562 if(m_nDefActivePane == SPLIT_PANE_LEFT || m_nDefActivePane == SPLIT_PANE_RIGHT)
\r
563 ::SetFocus(m_hWndPane[m_nDefActivePane]);
\r
567 ::SetFocus(m_hWndPane[m_nSinglePane]);
\r
574 LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
\r
576 T* pT = static_cast<T*>(this);
\r
577 LRESULT lRet = pT->DefWindowProc(uMsg, wParam, lParam);
\r
578 if(lRet == MA_ACTIVATE || lRet == MA_ACTIVATEANDEAT)
\r
580 DWORD dwPos = ::GetMessagePos();
\r
581 POINT pt = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) };
\r
582 pT->ScreenToClient(&pt);
\r
584 for(int nPane = 0; nPane < m_nPanesCount; nPane++)
\r
586 if(GetSplitterPaneRect(nPane, &rcPane) && ::PtInRect(&rcPane, pt))
\r
588 m_nDefActivePane = nPane;
\r
595 #endif // !_WIN32_WCE
\r
597 LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
\r
599 GetSystemSettings(true);
\r
603 // Implementation - internal helpers
\r
604 void UpdateSplitterLayout()
\r
606 if(m_nSinglePane == SPLIT_PANE_NONE && m_xySplitterPos == -1)
\r
609 T* pT = static_cast<T*>(this);
\r
610 RECT rect = { 0, 0, 0, 0 };
\r
611 if(m_nSinglePane == SPLIT_PANE_NONE)
\r
613 if(GetSplitterBarRect(&rect))
\r
614 pT->InvalidateRect(&rect);
\r
616 for(int nPane = 0; nPane < m_nPanesCount; nPane++)
\r
618 if(GetSplitterPaneRect(nPane, &rect))
\r
620 if(m_hWndPane[nPane] != NULL)
\r
621 ::SetWindowPos(m_hWndPane[nPane], NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
623 pT->InvalidateRect(&rect);
\r
629 if(GetSplitterPaneRect(m_nSinglePane, &rect))
\r
631 if(m_hWndPane[m_nSinglePane] != NULL)
\r
632 ::SetWindowPos(m_hWndPane[m_nSinglePane], NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
634 pT->InvalidateRect(&rect);
\r
639 bool GetSplitterBarRect(LPRECT lpRect) const
\r
641 ATLASSERT(lpRect != NULL);
\r
642 if(m_nSinglePane != SPLIT_PANE_NONE || m_xySplitterPos == -1)
\r
647 lpRect->left = m_rcSplitter.left + m_xySplitterPos;
\r
648 lpRect->top = m_rcSplitter.top;
\r
649 lpRect->right = m_rcSplitter.left + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge;
\r
650 lpRect->bottom = m_rcSplitter.bottom;
\r
654 lpRect->left = m_rcSplitter.left;
\r
655 lpRect->top = m_rcSplitter.top + m_xySplitterPos;
\r
656 lpRect->right = m_rcSplitter.right;
\r
657 lpRect->bottom = m_rcSplitter.top + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge;
\r
663 bool GetSplitterPaneRect(int nPane, LPRECT lpRect) const
\r
665 ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT);
\r
666 ATLASSERT(lpRect != NULL);
\r
668 if(m_nSinglePane != SPLIT_PANE_NONE)
\r
670 if(nPane == m_nSinglePane)
\r
671 *lpRect = m_rcSplitter;
\r
675 else if(nPane == SPLIT_PANE_LEFT)
\r
679 lpRect->left = m_rcSplitter.left;
\r
680 lpRect->top = m_rcSplitter.top;
\r
681 lpRect->right = m_rcSplitter.left + m_xySplitterPos;
\r
682 lpRect->bottom = m_rcSplitter.bottom;
\r
686 lpRect->left = m_rcSplitter.left;
\r
687 lpRect->top = m_rcSplitter.top;
\r
688 lpRect->right = m_rcSplitter.right;
\r
689 lpRect->bottom = m_rcSplitter.top + m_xySplitterPos;
\r
692 else if(nPane == SPLIT_PANE_RIGHT)
\r
696 lpRect->left = m_rcSplitter.left + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge;
\r
697 lpRect->top = m_rcSplitter.top;
\r
698 lpRect->right = m_rcSplitter.right;
\r
699 lpRect->bottom = m_rcSplitter.bottom;
\r
703 lpRect->left = m_rcSplitter.left;
\r
704 lpRect->top = m_rcSplitter.top + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge;
\r
705 lpRect->right = m_rcSplitter.right;
\r
706 lpRect->bottom = m_rcSplitter.bottom;
\r
716 bool IsOverSplitterRect(int x, int y) const
\r
718 // -1 == don't check
\r
719 return ((x == -1 || (x >= m_rcSplitter.left && x <= m_rcSplitter.right)) &&
\r
720 (y == -1 || (y >= m_rcSplitter.top && y <= m_rcSplitter.bottom)));
\r
723 bool IsOverSplitterBar(int x, int y) const
\r
725 if(m_nSinglePane != SPLIT_PANE_NONE)
\r
727 if(m_xySplitterPos == -1 || !IsOverSplitterRect(x, y))
\r
729 int xy = t_bVertical ? x : y;
\r
730 int xyOff = t_bVertical ? m_rcSplitter.left : m_rcSplitter.top;
\r
731 return ((xy >= (xyOff + m_xySplitterPos)) && (xy < xyOff + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge));
\r
734 void DrawGhostBar()
\r
736 RECT rect = { 0, 0, 0, 0 };
\r
737 if(GetSplitterBarRect(&rect))
\r
739 // invert the brush pattern (looks just like frame window sizing)
\r
740 T* pT = static_cast<T*>(this);
\r
741 CWindowDC dc(pT->m_hWnd);
\r
742 CBrush brush = CDCHandle::GetHalftoneBrush();
\r
743 if(brush.m_hBrush != NULL)
\r
745 CBrushHandle brushOld = dc.SelectBrush(brush);
\r
746 dc.PatBlt(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, PATINVERT);
\r
747 dc.SelectBrush(brushOld);
\r
752 void GetSystemSettings(bool bUpdate)
\r
755 m_cxySplitBar = ::GetSystemMetrics(t_bVertical ? SM_CXSIZEFRAME : SM_CYSIZEFRAME);
\r
756 #else // CE specific
\r
757 m_cxySplitBar = 2 * ::GetSystemMetrics(t_bVertical ? SM_CXEDGE : SM_CYEDGE);
\r
758 #endif // _WIN32_WCE
\r
760 T* pT = static_cast<T*>(this);
\r
761 if((pT->GetExStyle() & WS_EX_CLIENTEDGE))
\r
763 m_cxyBarEdge = 2 * ::GetSystemMetrics(t_bVertical ? SM_CXEDGE : SM_CYEDGE);
\r
769 m_cxyMin = 2 * ::GetSystemMetrics(t_bVertical ? SM_CXEDGE : SM_CYEDGE);
\r
773 ::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &m_bFullDrag, 0);
\r
774 #endif // !_WIN32_WCE
\r
777 UpdateSplitterLayout();
\r
780 bool IsProportional() const
\r
782 return ((m_dwExtendedStyle & SPLIT_PROPORTIONAL) != 0);
\r
785 void StoreProportionalPos()
\r
787 int cxyTotal = t_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge);
\r
789 m_nProportionalPos = ::MulDiv(m_xySplitterPos, m_nPropMax, cxyTotal);
\r
791 m_nProportionalPos = 0;
\r
792 ATLTRACE2(atlTraceUI, 0, _T("CSplitterImpl::StoreProportionalPos - %i\n"), m_nProportionalPos);
\r
795 void UpdateProportionalPos()
\r
797 int cxyTotal = t_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge);
\r
800 int xyNewPos = ::MulDiv(m_nProportionalPos, cxyTotal, m_nPropMax);
\r
801 m_bUpdateProportionalPos = false;
\r
802 T* pT = static_cast<T*>(this);
\r
803 pT->SetSplitterPos(xyNewPos, false);
\r
807 bool IsRightAligned() const
\r
809 return ((m_dwExtendedStyle & SPLIT_RIGHTALIGNED) != 0);
\r
812 void StoreRightAlignPos()
\r
814 int cxyTotal = t_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge);
\r
816 m_nProportionalPos = cxyTotal - m_xySplitterPos;
\r
818 m_nProportionalPos = 0;
\r
819 ATLTRACE2(atlTraceUI, 0, _T("CSplitterImpl::StoreRightAlignPos - %i\n"), m_nProportionalPos);
\r
822 void UpdateRightAlignPos()
\r
824 int cxyTotal = t_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge);
\r
827 m_bUpdateProportionalPos = false;
\r
828 T* pT = static_cast<T*>(this);
\r
829 pT->SetSplitterPos(cxyTotal - m_nProportionalPos, false);
\r
833 bool IsInteractive() const
\r
835 return ((m_dwExtendedStyle & SPLIT_NONINTERACTIVE) == 0);
\r
839 template <class T, bool t_bVertical> HCURSOR CSplitterImpl< T, t_bVertical>::m_hCursor = NULL;
\r
842 ///////////////////////////////////////////////////////////////////////////////
\r
843 // CSplitterWindowImpl - Implements a splitter window
\r
845 template <class T, bool t_bVertical = true, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
\r
846 class ATL_NO_VTABLE CSplitterWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CSplitterImpl< T , t_bVertical >
\r
849 DECLARE_WND_CLASS_EX(NULL, CS_DBLCLKS, COLOR_WINDOW)
\r
851 typedef CSplitterImpl< T , t_bVertical > _baseClass;
\r
853 BEGIN_MSG_MAP(CSplitterWindowImpl)
\r
854 MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
\r
855 MESSAGE_HANDLER(WM_SIZE, OnSize)
\r
856 CHAIN_MSG_MAP(_baseClass)
\r
857 FORWARD_NOTIFICATIONS()
\r
860 LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
\r
862 // handled, no background painting needed
\r
866 LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
\r
868 if(wParam != SIZE_MINIMIZED)
\r
877 ///////////////////////////////////////////////////////////////////////////////
\r
878 // CSplitterWindow - Implements a splitter window to be used as is
\r
880 template <bool t_bVertical = true>
\r
881 class CSplitterWindowT : public CSplitterWindowImpl<CSplitterWindowT<t_bVertical>, t_bVertical>
\r
884 DECLARE_WND_CLASS_EX(_T("WTL_SplitterWindow"), CS_DBLCLKS, COLOR_WINDOW)
\r
887 typedef CSplitterWindowT<true> CSplitterWindow;
\r
888 typedef CSplitterWindowT<false> CHorSplitterWindow;
\r
890 }; // namespace WTL
\r
892 #endif // __ATLSPLIT_H__
\r