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__