1 // Windows Template Library - WTL version 9.10
2 // Copyright (C) Microsoft Corporation, WTL Team. All rights reserved.
3 //
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 Public License (http://opensource.org/licenses/MS-PL)
7 // which can be found in the file MS-PL.txt at the root folder.
8 
9 #ifndef __ATLSPLIT_H__
10 #define __ATLSPLIT_H__
11 
12 #pragma once
13 
14 #ifndef __ATLAPP_H__
15 	#error atlsplit.h requires atlapp.h to be included first
16 #endif
17 
18 #ifndef __ATLWIN_H__
19 	#error atlsplit.h requires atlwin.h to be included first
20 #endif
21 
22 
23 ///////////////////////////////////////////////////////////////////////////////
24 // Classes in this file:
25 //
26 // CSplitterImpl<T>
27 // CSplitterWindowImpl<T, TBase, TWinTraits>
28 // CSplitterWindowT<t_bVertical> - CSplitterWindow, CHorSplitterWindow
29 
30 
31 namespace WTL
32 {
33 
34 ///////////////////////////////////////////////////////////////////////////////
35 // CSplitterImpl - Provides splitter support to any window
36 
37 // Splitter panes constants
38 #define SPLIT_PANE_LEFT			 0
39 #define SPLIT_PANE_RIGHT		 1
40 #define SPLIT_PANE_TOP			 SPLIT_PANE_LEFT
41 #define SPLIT_PANE_BOTTOM		 SPLIT_PANE_RIGHT
42 #define SPLIT_PANE_NONE			-1
43 
44 // Splitter extended styles
45 #define SPLIT_PROPORTIONAL		0x00000001
46 #define SPLIT_NONINTERACTIVE		0x00000002
47 #define SPLIT_RIGHTALIGNED		0x00000004
48 #define SPLIT_BOTTOMALIGNED		SPLIT_RIGHTALIGNED
49 #define SPLIT_GRADIENTBAR		0x00000008
50 #define SPLIT_FIXEDBARSIZE		0x00000010
51 
52 // Note: SPLIT_PROPORTIONAL and SPLIT_RIGHTALIGNED/SPLIT_BOTTOMALIGNED are
53 // mutually exclusive. If both are set, splitter defaults to SPLIT_PROPORTIONAL.
54 // SPLIT_GRADIENTBAR doesn't work with _ATL_NO_MSIMG
55 
56 
57 template <class T>
58 class CSplitterImpl
59 {
60 public:
61 	enum { m_nPanesCount = 2, m_nPropMax = 10000, m_cxyStep = 10 };
62 
63 	bool m_bVertical;
64 	HWND m_hWndPane[m_nPanesCount];
65 	RECT m_rcSplitter;
66 	int m_xySplitterPos;            // splitter bar position
67 	int m_xySplitterPosNew;         // internal - new position while moving
68 	HWND m_hWndFocusSave;
69 	int m_nDefActivePane;
70 	int m_cxySplitBar;              // splitter bar width/height
71 	HCURSOR m_hCursor;
72 	int m_cxyMin;                   // minimum pane size
73 	int m_cxyBarEdge;              	// splitter bar edge
74 	bool m_bFullDrag;
75 	int m_cxyDragOffset;		// internal
76 	int m_nProportionalPos;
77 	bool m_bUpdateProportionalPos;
78 	DWORD m_dwExtendedStyle;        // splitter specific extended styles
79 	int m_nSinglePane;              // single pane mode
80 	int m_xySplitterDefPos;         // default position
81 	bool m_bProportionalDefPos;     // porportinal def pos
82 
83 // Constructor
84 	CSplitterImpl(bool bVertical = true) :
m_bVertical(bVertical)85 	              m_bVertical(bVertical), m_xySplitterPos(-1), m_xySplitterPosNew(-1), m_hWndFocusSave(NULL),
86 	              m_nDefActivePane(SPLIT_PANE_NONE), m_cxySplitBar(4), m_hCursor(NULL), m_cxyMin(0), m_cxyBarEdge(0),
87 	              m_bFullDrag(true), m_cxyDragOffset(0), m_nProportionalPos(0), m_bUpdateProportionalPos(true),
88 	              m_dwExtendedStyle(SPLIT_PROPORTIONAL), m_nSinglePane(SPLIT_PANE_NONE),
89 	              m_xySplitterDefPos(-1), m_bProportionalDefPos(false)
90 	{
91 		m_hWndPane[SPLIT_PANE_LEFT] = NULL;
92 		m_hWndPane[SPLIT_PANE_RIGHT] = NULL;
93 
94 		::SetRectEmpty(&m_rcSplitter);
95 	}
96 
97 // Attributes
98 	void SetSplitterRect(LPRECT lpRect = NULL, bool bUpdate = true)
99 	{
100 		if(lpRect == NULL)
101 		{
102 			T* pT = static_cast<T*>(this);
103 			pT->GetClientRect(&m_rcSplitter);
104 		}
105 		else
106 		{
107 			m_rcSplitter = *lpRect;
108 		}
109 
110 		if(IsProportional())
111 			UpdateProportionalPos();
112 		else if(IsRightAligned())
113 			UpdateRightAlignPos();
114 
115 		if(bUpdate)
116 			UpdateSplitterLayout();
117 	}
118 
GetSplitterRect(LPRECT lpRect)119 	void GetSplitterRect(LPRECT lpRect) const
120 	{
121 		ATLASSERT(lpRect != NULL);
122 		*lpRect = m_rcSplitter;
123 	}
124 
125 	bool SetSplitterPos(int xyPos = -1, bool bUpdate = true)
126 	{
127 		if(xyPos == -1)   // -1 == default position
128 		{
129 			if(m_bProportionalDefPos)
130 			{
131 				ATLASSERT((m_xySplitterDefPos >= 0) && (m_xySplitterDefPos <= m_nPropMax));
132 
133 				if(m_bVertical)
134 					xyPos = ::MulDiv(m_xySplitterDefPos, m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge, m_nPropMax);
135 				else
136 					xyPos = ::MulDiv(m_xySplitterDefPos, m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge, m_nPropMax);
137 			}
138 			else if(m_xySplitterDefPos != -1)
139 			{
140 				xyPos = m_xySplitterDefPos;
141 			}
142 			else   // not set, use middle position
143 			{
144 				if(m_bVertical)
145 					xyPos = (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) / 2;
146 				else
147 					xyPos = (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge) / 2;
148 			}
149 		}
150 
151 		// Adjust if out of valid range
152 		int cxyMax = 0;
153 		if(m_bVertical)
154 			cxyMax = m_rcSplitter.right - m_rcSplitter.left;
155 		else
156 			cxyMax = m_rcSplitter.bottom - m_rcSplitter.top;
157 
158 		if(xyPos < m_cxyMin + m_cxyBarEdge)
159 			xyPos = m_cxyMin;
160 		else if(xyPos > (cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin))
161 			xyPos = cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin;
162 
163 		// Set new position and update if requested
164 		bool bRet = (m_xySplitterPos != xyPos);
165 		m_xySplitterPos = xyPos;
166 
167 		if(m_bUpdateProportionalPos)
168 		{
169 			if(IsProportional())
170 				StoreProportionalPos();
171 			else if(IsRightAligned())
172 				StoreRightAlignPos();
173 		}
174 		else
175 		{
176 			m_bUpdateProportionalPos = true;
177 		}
178 
179 		if(bUpdate && bRet)
180 			UpdateSplitterLayout();
181 
182 		return bRet;
183 	}
184 
GetSplitterPos()185 	int GetSplitterPos() const
186 	{
187 		return m_xySplitterPos;
188 	}
189 
190 	void SetSplitterPosPct(int nPct, bool bUpdate = true)
191 	{
192 		ATLASSERT((nPct >= 0) && (nPct <= 100));
193 
194 		m_nProportionalPos = ::MulDiv(nPct, m_nPropMax, 100);
195 		UpdateProportionalPos();
196 
197 		if(bUpdate)
198 			UpdateSplitterLayout();
199 	}
200 
GetSplitterPosPct()201 	int GetSplitterPosPct() const
202 	{
203 		int cxyTotal = m_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge);
204 		return ((cxyTotal > 0) && (m_xySplitterPos >= 0)) ? (::MulDiv(m_xySplitterPos, m_nPropMax, cxyTotal) / 100) : -1;
205 	}
206 
207 	bool SetSinglePaneMode(int nPane = SPLIT_PANE_NONE)
208 	{
209 		ATLASSERT((nPane == SPLIT_PANE_LEFT) || (nPane == SPLIT_PANE_RIGHT) || (nPane == SPLIT_PANE_NONE));
210 		if(!((nPane == SPLIT_PANE_LEFT) || (nPane == SPLIT_PANE_RIGHT) || (nPane == SPLIT_PANE_NONE)))
211 			return false;
212 
213 		if(nPane != SPLIT_PANE_NONE)
214 		{
215 			if(::IsWindowVisible(m_hWndPane[nPane]) == FALSE)
216 				::ShowWindow(m_hWndPane[nPane], SW_SHOW);
217 			int nOtherPane = (nPane == SPLIT_PANE_LEFT) ? SPLIT_PANE_RIGHT : SPLIT_PANE_LEFT;
218 			::ShowWindow(m_hWndPane[nOtherPane], SW_HIDE);
219 			if(m_nDefActivePane != nPane)
220 				m_nDefActivePane = nPane;
221 		}
222 		else if(m_nSinglePane != SPLIT_PANE_NONE)
223 		{
224 			int nOtherPane = (m_nSinglePane == SPLIT_PANE_LEFT) ? SPLIT_PANE_RIGHT : SPLIT_PANE_LEFT;
225 			::ShowWindow(m_hWndPane[nOtherPane], SW_SHOW);
226 		}
227 
228 		m_nSinglePane = nPane;
229 		UpdateSplitterLayout();
230 
231 		return true;
232 	}
233 
GetSinglePaneMode()234 	int GetSinglePaneMode() const
235 	{
236 		return m_nSinglePane;
237 	}
238 
GetSplitterExtendedStyle()239 	DWORD GetSplitterExtendedStyle() const
240 	{
241 		return m_dwExtendedStyle;
242 	}
243 
244 	DWORD SetSplitterExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)
245 	{
246 		DWORD dwPrevStyle = m_dwExtendedStyle;
247 		if(dwMask == 0)
248 			m_dwExtendedStyle = dwExtendedStyle;
249 		else
250 			m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);
251 
252 #ifdef _DEBUG
253 		if(IsProportional() && IsRightAligned())
254 			ATLTRACE2(atlTraceUI, 0, _T("CSplitterImpl::SetSplitterExtendedStyle - SPLIT_PROPORTIONAL and SPLIT_RIGHTALIGNED are mutually exclusive, defaulting to SPLIT_PROPORTIONAL.\n"));
255 #endif // _DEBUG
256 
257 		return dwPrevStyle;
258 	}
259 
260 	void SetSplitterDefaultPos(int xyPos = -1)
261 	{
262 		m_xySplitterDefPos = xyPos;
263 		m_bProportionalDefPos = false;
264 	}
265 
SetSplitterDefaultPosPct(int nPct)266 	void SetSplitterDefaultPosPct(int nPct)
267 	{
268 		ATLASSERT((nPct >= 0) && (nPct <= 100));
269 
270 		m_xySplitterDefPos = ::MulDiv(nPct, m_nPropMax, 100);
271 		m_bProportionalDefPos = true;
272 	}
273 
274 // Splitter operations
275 	void SetSplitterPanes(HWND hWndLeftTop, HWND hWndRightBottom, bool bUpdate = true)
276 	{
277 		m_hWndPane[SPLIT_PANE_LEFT] = hWndLeftTop;
278 		m_hWndPane[SPLIT_PANE_RIGHT] = hWndRightBottom;
279 		ATLASSERT((m_hWndPane[SPLIT_PANE_LEFT] == NULL) || (m_hWndPane[SPLIT_PANE_RIGHT] == NULL) || (m_hWndPane[SPLIT_PANE_LEFT] != m_hWndPane[SPLIT_PANE_RIGHT]));
280 		if(bUpdate)
281 			UpdateSplitterLayout();
282 	}
283 
284 	bool SetSplitterPane(int nPane, HWND hWnd, bool bUpdate = true)
285 	{
286 		ATLASSERT((nPane == SPLIT_PANE_LEFT) || (nPane == SPLIT_PANE_RIGHT));
287 		if((nPane != SPLIT_PANE_LEFT) && (nPane != SPLIT_PANE_RIGHT))
288 			return false;
289 
290 		m_hWndPane[nPane] = hWnd;
291 		ATLASSERT((m_hWndPane[SPLIT_PANE_LEFT] == NULL) || (m_hWndPane[SPLIT_PANE_RIGHT] == NULL) || (m_hWndPane[SPLIT_PANE_LEFT] != m_hWndPane[SPLIT_PANE_RIGHT]));
292 		if(bUpdate)
293 			UpdateSplitterLayout();
294 
295 		return true;
296 	}
297 
GetSplitterPane(int nPane)298 	HWND GetSplitterPane(int nPane) const
299 	{
300 		ATLASSERT((nPane == SPLIT_PANE_LEFT) || (nPane == SPLIT_PANE_RIGHT));
301 		if((nPane != SPLIT_PANE_LEFT) && (nPane != SPLIT_PANE_RIGHT))
302 			return NULL;
303 
304 		return m_hWndPane[nPane];
305 	}
306 
SetActivePane(int nPane)307 	bool SetActivePane(int nPane)
308 	{
309 		ATLASSERT((nPane == SPLIT_PANE_LEFT) || (nPane == SPLIT_PANE_RIGHT));
310 		if((nPane != SPLIT_PANE_LEFT) && (nPane != SPLIT_PANE_RIGHT))
311 			return false;
312 		if((m_nSinglePane != SPLIT_PANE_NONE) && (nPane != m_nSinglePane))
313 			return false;
314 
315 		::SetFocus(m_hWndPane[nPane]);
316 		m_nDefActivePane = nPane;
317 
318 		return true;
319 	}
320 
GetActivePane()321 	int GetActivePane() const
322 	{
323 		int nRet = SPLIT_PANE_NONE;
324 		HWND hWndFocus = ::GetFocus();
325 		if(hWndFocus != NULL)
326 		{
327 			for(int nPane = 0; nPane < m_nPanesCount; nPane++)
328 			{
329 				if((hWndFocus == m_hWndPane[nPane]) || (::IsChild(m_hWndPane[nPane], hWndFocus) != FALSE))
330 				{
331 					nRet = nPane;
332 					break;
333 				}
334 			}
335 		}
336 
337 		return nRet;
338 	}
339 
340 	bool ActivateNextPane(bool bNext = true)
341 	{
342 		int nPane = m_nSinglePane;
343 		if(nPane == SPLIT_PANE_NONE)
344 		{
345 			switch(GetActivePane())
346 			{
347 			case SPLIT_PANE_LEFT:
348 				nPane = SPLIT_PANE_RIGHT;
349 				break;
350 			case SPLIT_PANE_RIGHT:
351 				nPane = SPLIT_PANE_LEFT;
352 				break;
353 			default:
354 				nPane = bNext ? SPLIT_PANE_LEFT : SPLIT_PANE_RIGHT;
355 				break;
356 			}
357 		}
358 
359 		return SetActivePane(nPane);
360 	}
361 
SetDefaultActivePane(int nPane)362 	bool SetDefaultActivePane(int nPane)
363 	{
364 		ATLASSERT((nPane == SPLIT_PANE_LEFT) || (nPane == SPLIT_PANE_RIGHT));
365 		if((nPane != SPLIT_PANE_LEFT) && (nPane != SPLIT_PANE_RIGHT))
366 			return false;
367 
368 		m_nDefActivePane = nPane;
369 
370 		return true;
371 	}
372 
SetDefaultActivePane(HWND hWnd)373 	bool SetDefaultActivePane(HWND hWnd)
374 	{
375 		for(int nPane = 0; nPane < m_nPanesCount; nPane++)
376 		{
377 			if(hWnd == m_hWndPane[nPane])
378 			{
379 				m_nDefActivePane = nPane;
380 				return true;
381 			}
382 		}
383 
384 		return false;   // not found
385 	}
386 
GetDefaultActivePane()387 	int GetDefaultActivePane() const
388 	{
389 		return m_nDefActivePane;
390 	}
391 
DrawSplitter(CDCHandle dc)392 	void DrawSplitter(CDCHandle dc)
393 	{
394 		ATLASSERT(dc.m_hDC != NULL);
395 		if((m_nSinglePane == SPLIT_PANE_NONE) && (m_xySplitterPos == -1))
396 			return;
397 
398 		T* pT = static_cast<T*>(this);
399 		if(m_nSinglePane == SPLIT_PANE_NONE)
400 		{
401 			pT->DrawSplitterBar(dc);
402 
403 			for(int nPane = 0; nPane < m_nPanesCount; nPane++)
404 			{
405 				if(m_hWndPane[nPane] == NULL)
406 					pT->DrawSplitterPane(dc, nPane);
407 			}
408 		}
409 		else
410 		{
411 			if(m_hWndPane[m_nSinglePane] == NULL)
412 				pT->DrawSplitterPane(dc, m_nSinglePane);
413 		}
414 	}
415 
416 	// call to initiate moving splitter bar with keyboard
MoveSplitterBar()417 	void MoveSplitterBar()
418 	{
419 		T* pT = static_cast<T*>(this);
420 
421 		int x = 0;
422 		int y = 0;
423 		if(m_bVertical)
424 		{
425 			x = m_xySplitterPos + (m_cxySplitBar / 2) + m_cxyBarEdge;
426 			y = (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge) / 2;
427 		}
428 		else
429 		{
430 			x = (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) / 2;
431 			y = m_xySplitterPos + (m_cxySplitBar / 2) + m_cxyBarEdge;
432 		}
433 
434 		POINT pt = { x, y };
435 		pT->ClientToScreen(&pt);
436 		::SetCursorPos(pt.x, pt.y);
437 
438 		m_xySplitterPosNew = m_xySplitterPos;
439 		pT->SetCapture();
440 		m_hWndFocusSave = pT->SetFocus();
441 		::SetCursor(m_hCursor);
442 		if(!m_bFullDrag)
443 			DrawGhostBar();
444 		if(m_bVertical)
445 			m_cxyDragOffset = x - m_rcSplitter.left - m_xySplitterPos;
446 		else
447 			m_cxyDragOffset = y - m_rcSplitter.top - m_xySplitterPos;
448 	}
449 
450 	void SetOrientation(bool bVertical, bool bUpdate = true)
451 	{
452 		if(m_bVertical != bVertical)
453 		{
454 			m_bVertical = bVertical;
455 
456 			m_hCursor = ::LoadCursor(NULL, m_bVertical ? IDC_SIZEWE : IDC_SIZENS);
457 
458 			T* pT = static_cast<T*>(this);
459 			pT->GetSystemSettings(false);
460 
461 			if(m_bVertical)
462 				m_xySplitterPos = ::MulDiv(m_xySplitterPos, m_rcSplitter.right - m_rcSplitter.left, m_rcSplitter.bottom - m_rcSplitter.top);
463 			else
464 				m_xySplitterPos = ::MulDiv(m_xySplitterPos, m_rcSplitter.bottom - m_rcSplitter.top, m_rcSplitter.right - m_rcSplitter.left);
465 		}
466 
467 		if(bUpdate)
468 			UpdateSplitterLayout();
469 	}
470 
471 // Overrideables
DrawSplitterBar(CDCHandle dc)472 	void DrawSplitterBar(CDCHandle dc)
473 	{
474 		RECT rect = { 0 };
475 		if(GetSplitterBarRect(&rect))
476 		{
477 			dc.FillRect(&rect, COLOR_3DFACE);
478 
479 #if (!defined(_WIN32_WCE) && !defined(_ATL_NO_MSIMG)) || (_WIN32_WCE >= 420)
480 			if((m_dwExtendedStyle & SPLIT_GRADIENTBAR) != 0)
481 			{
482 				RECT rect2 = rect;
483 				if(m_bVertical)
484 					rect2.left = (rect.left + rect.right) / 2 - 1;
485 				else
486 					rect2.top = (rect.top + rect.bottom) / 2 - 1;
487 
488 				dc.GradientFillRect(rect2, ::GetSysColor(COLOR_3DFACE), ::GetSysColor(COLOR_3DSHADOW), m_bVertical);
489 			}
490 #endif // (!defined(_WIN32_WCE) && !defined(_ATL_NO_MSIMG)) || (_WIN32_WCE >= 420)
491 
492 			// draw 3D edge if needed
493 			T* pT = static_cast<T*>(this);
494 			if((pT->GetExStyle() & WS_EX_CLIENTEDGE) != 0)
495 				dc.DrawEdge(&rect, EDGE_RAISED, m_bVertical ? (BF_LEFT | BF_RIGHT) : (BF_TOP | BF_BOTTOM));
496 		}
497 	}
498 
499 	// called only if pane is empty
DrawSplitterPane(CDCHandle dc,int nPane)500 	void DrawSplitterPane(CDCHandle dc, int nPane)
501 	{
502 		RECT rect = { 0 };
503 		if(GetSplitterPaneRect(nPane, &rect))
504 		{
505 			T* pT = static_cast<T*>(this);
506 			if((pT->GetExStyle() & WS_EX_CLIENTEDGE) == 0)
507 				dc.DrawEdge(&rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
508 			dc.FillRect(&rect, COLOR_APPWORKSPACE);
509 		}
510 	}
511 
512 // Message map and handlers
513 	BEGIN_MSG_MAP(CSplitterImpl)
514 		MESSAGE_HANDLER(WM_CREATE, OnCreate)
515 		MESSAGE_HANDLER(WM_PAINT, OnPaint)
516 #ifndef _WIN32_WCE
517 		MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
518 #endif // !_WIN32_WCE
519 		if(IsInteractive())
520 		{
521 			MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor)
522 			MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
523 			MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
524 			MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
525 			MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDoubleClick)
526 			MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged)
527 			MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)
528 		}
MESSAGE_HANDLER(WM_SETFOCUS,OnSetFocus)529 		MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
530 #ifndef _WIN32_WCE
531 		MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate)
532 #endif // !_WIN32_WCE
533 		MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)
534 	END_MSG_MAP()
535 
536 	LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
537 	{
538 		T* pT = static_cast<T*>(this);
539 		pT->Init();
540 
541 		bHandled = FALSE;
542 		return 1;
543 	}
544 
OnPaint(UINT,WPARAM wParam,LPARAM,BOOL &)545 	LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
546 	{
547 		T* pT = static_cast<T*>(this);
548 
549 		// try setting position if not set
550 		if((m_nSinglePane == SPLIT_PANE_NONE) && (m_xySplitterPos == -1))
551 			pT->SetSplitterPos();
552 
553 		// do painting
554 		if(wParam != NULL)
555 		{
556 			pT->DrawSplitter((HDC)wParam);
557 		}
558 		else
559 		{
560 			CPaintDC dc(pT->m_hWnd);
561 			pT->DrawSplitter(dc.m_hDC);
562 		}
563 
564 		return 0;
565 	}
566 
OnSetCursor(UINT,WPARAM wParam,LPARAM lParam,BOOL & bHandled)567 	LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
568 	{
569 		T* pT = static_cast<T*>(this);
570 		if(((HWND)wParam == pT->m_hWnd) && (LOWORD(lParam) == HTCLIENT))
571 		{
572 			DWORD dwPos = ::GetMessagePos();
573 			POINT ptPos = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) };
574 			pT->ScreenToClient(&ptPos);
575 			if(IsOverSplitterBar(ptPos.x, ptPos.y))
576 				return 1;
577 		}
578 
579 		bHandled = FALSE;
580 		return 0;
581 	}
582 
OnMouseMove(UINT,WPARAM,LPARAM lParam,BOOL & bHandled)583 	LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
584 	{
585 		T* pT = static_cast<T*>(this);
586 		int xPos = GET_X_LPARAM(lParam);
587 		int yPos = GET_Y_LPARAM(lParam);
588 		if(::GetCapture() == pT->m_hWnd)
589 		{
590 			int xyNewSplitPos = 0;
591 			if(m_bVertical)
592 				xyNewSplitPos = xPos - m_rcSplitter.left - m_cxyDragOffset;
593 			else
594 				xyNewSplitPos = yPos - m_rcSplitter.top - m_cxyDragOffset;
595 
596 			if(xyNewSplitPos == -1)   // avoid -1, that means default position
597 				xyNewSplitPos = -2;
598 
599 			if(m_xySplitterPos != xyNewSplitPos)
600 			{
601 				if(m_bFullDrag)
602 				{
603 					if(pT->SetSplitterPos(xyNewSplitPos, true))
604 						pT->UpdateWindow();
605 				}
606 				else
607 				{
608 					DrawGhostBar();
609 					pT->SetSplitterPos(xyNewSplitPos, false);
610 					DrawGhostBar();
611 				}
612 			}
613 		}
614 		else		// not dragging, just set cursor
615 		{
616 			if(IsOverSplitterBar(xPos, yPos))
617 				::SetCursor(m_hCursor);
618 			bHandled = FALSE;
619 		}
620 
621 		return 0;
622 	}
623 
OnLButtonDown(UINT,WPARAM,LPARAM lParam,BOOL & bHandled)624 	LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
625 	{
626 		T* pT = static_cast<T*>(this);
627 		int xPos = GET_X_LPARAM(lParam);
628 		int yPos = GET_Y_LPARAM(lParam);
629 		if((::GetCapture() != pT->m_hWnd) && IsOverSplitterBar(xPos, yPos))
630 		{
631 			m_xySplitterPosNew = m_xySplitterPos;
632 			pT->SetCapture();
633 			m_hWndFocusSave = pT->SetFocus();
634 			::SetCursor(m_hCursor);
635 			if(!m_bFullDrag)
636 				DrawGhostBar();
637 			if(m_bVertical)
638 				m_cxyDragOffset = xPos - m_rcSplitter.left - m_xySplitterPos;
639 			else
640 				m_cxyDragOffset = yPos - m_rcSplitter.top - m_xySplitterPos;
641 		}
642 		else if((::GetCapture() == pT->m_hWnd) && !IsOverSplitterBar(xPos, yPos))
643 		{
644 			::ReleaseCapture();
645 		}
646 
647 		bHandled = FALSE;
648 		return 1;
649 	}
650 
OnLButtonUp(UINT,WPARAM,LPARAM,BOOL & bHandled)651 	LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
652 	{
653 		T* pT = static_cast<T*>(this);
654 		if(::GetCapture() == pT->m_hWnd)
655 		{
656 			m_xySplitterPosNew = m_xySplitterPos;
657 			::ReleaseCapture();
658 		}
659 
660 		bHandled = FALSE;
661 		return 1;
662 	}
663 
OnLButtonDoubleClick(UINT,WPARAM,LPARAM,BOOL &)664 	LRESULT OnLButtonDoubleClick(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
665 	{
666 		T* pT = static_cast<T*>(this);
667 		pT->SetSplitterPos();   // default
668 
669 		return 0;
670 	}
671 
OnCaptureChanged(UINT,WPARAM,LPARAM,BOOL &)672 	LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
673 	{
674 		if(!m_bFullDrag)
675 			DrawGhostBar();
676 
677 		if((m_xySplitterPosNew != -1) && (!m_bFullDrag || (m_xySplitterPos != m_xySplitterPosNew)))
678 		{
679 			m_xySplitterPos = m_xySplitterPosNew;
680 			m_xySplitterPosNew = -1;
681 			UpdateSplitterLayout();
682 			T* pT = static_cast<T*>(this);
683 			pT->UpdateWindow();
684 		}
685 
686 		if(m_hWndFocusSave != NULL)
687 			::SetFocus(m_hWndFocusSave);
688 
689 		return 0;
690 	}
691 
OnKeyDown(UINT,WPARAM wParam,LPARAM,BOOL & bHandled)692 	LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
693 	{
694 		T* pT = static_cast<T*>(this);
695 		if(::GetCapture() == pT->m_hWnd)
696 		{
697 			switch(wParam)
698 			{
699 			case VK_RETURN:
700 				m_xySplitterPosNew = m_xySplitterPos;
701 			case VK_ESCAPE:
702 				::ReleaseCapture();
703 				break;
704 			case VK_LEFT:
705 			case VK_RIGHT:
706 				if(m_bVertical)
707 				{
708 					POINT pt = { 0, 0 };
709 					::GetCursorPos(&pt);
710 					int xyPos = m_xySplitterPos + ((wParam == VK_LEFT) ? -pT->m_cxyStep : pT->m_cxyStep);
711 					int cxyMax = m_rcSplitter.right - m_rcSplitter.left;
712 					if(xyPos < (m_cxyMin + m_cxyBarEdge))
713 						xyPos = m_cxyMin;
714 					else if(xyPos > (cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin))
715 						xyPos = cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin;
716 					pt.x += xyPos - m_xySplitterPos;
717 					::SetCursorPos(pt.x, pt.y);
718 				}
719 				break;
720 			case VK_UP:
721 			case VK_DOWN:
722 				if(!m_bVertical)
723 				{
724 					POINT pt = { 0, 0 };
725 					::GetCursorPos(&pt);
726 					int xyPos = m_xySplitterPos + ((wParam == VK_UP) ? -pT->m_cxyStep : pT->m_cxyStep);
727 					int cxyMax = m_rcSplitter.bottom - m_rcSplitter.top;
728 					if(xyPos < (m_cxyMin + m_cxyBarEdge))
729 						xyPos = m_cxyMin;
730 					else if(xyPos > (cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin))
731 						xyPos = cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin;
732 					pt.y += xyPos - m_xySplitterPos;
733 					::SetCursorPos(pt.x, pt.y);
734 				}
735 				break;
736 			default:
737 				break;
738 			}
739 		}
740 		else
741 		{
742 			bHandled = FALSE;
743 		}
744 
745 		return 0;
746 	}
747 
OnSetFocus(UINT,WPARAM,LPARAM,BOOL & bHandled)748 	LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM, BOOL& bHandled)
749 	{
750 		T* pT = static_cast<T*>(this);
751 		if(::GetCapture() != pT->m_hWnd)
752 		{
753 			if(m_nSinglePane == SPLIT_PANE_NONE)
754 			{
755 				if((m_nDefActivePane == SPLIT_PANE_LEFT) || (m_nDefActivePane == SPLIT_PANE_RIGHT))
756 					::SetFocus(m_hWndPane[m_nDefActivePane]);
757 			}
758 			else
759 			{
760 				::SetFocus(m_hWndPane[m_nSinglePane]);
761 			}
762 		}
763 
764 		bHandled = FALSE;
765 		return 1;
766 	}
767 
768 #ifndef _WIN32_WCE
OnMouseActivate(UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL &)769 	LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
770 	{
771 		T* pT = static_cast<T*>(this);
772 		LRESULT lRet = pT->DefWindowProc(uMsg, wParam, lParam);
773 		if((lRet == MA_ACTIVATE) || (lRet == MA_ACTIVATEANDEAT))
774 		{
775 			DWORD dwPos = ::GetMessagePos();
776 			POINT pt = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) };
777 			pT->ScreenToClient(&pt);
778 			RECT rcPane = { 0 };
779 			for(int nPane = 0; nPane < m_nPanesCount; nPane++)
780 			{
781 				if(GetSplitterPaneRect(nPane, &rcPane) && (::PtInRect(&rcPane, pt) != FALSE))
782 				{
783 					m_nDefActivePane = nPane;
784 					break;
785 				}
786 			}
787 		}
788 
789 		return lRet;
790 	}
791 #endif // !_WIN32_WCE
792 
OnSettingChange(UINT,WPARAM,LPARAM,BOOL &)793 	LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
794 	{
795 		T* pT = static_cast<T*>(this);
796 		pT->GetSystemSettings(true);
797 
798 		return 0;
799 	}
800 
801 // Implementation - internal helpers
Init()802 	void Init()
803 	{
804 		m_hCursor = ::LoadCursor(NULL, m_bVertical ? IDC_SIZEWE : IDC_SIZENS);
805 
806 		T* pT = static_cast<T*>(this);
807 		pT->GetSystemSettings(false);
808 	}
809 
UpdateSplitterLayout()810 	void UpdateSplitterLayout()
811 	{
812 		if((m_nSinglePane == SPLIT_PANE_NONE) && (m_xySplitterPos == -1))
813 			return;
814 
815 		T* pT = static_cast<T*>(this);
816 		RECT rect = { 0 };
817 		if(m_nSinglePane == SPLIT_PANE_NONE)
818 		{
819 			if(GetSplitterBarRect(&rect))
820 				pT->InvalidateRect(&rect);
821 
822 			for(int nPane = 0; nPane < m_nPanesCount; nPane++)
823 			{
824 				if(GetSplitterPaneRect(nPane, &rect))
825 				{
826 					if(m_hWndPane[nPane] != NULL)
827 						::SetWindowPos(m_hWndPane[nPane], NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
828 					else
829 						pT->InvalidateRect(&rect);
830 				}
831 			}
832 		}
833 		else
834 		{
835 			if(GetSplitterPaneRect(m_nSinglePane, &rect))
836 			{
837 				if(m_hWndPane[m_nSinglePane] != NULL)
838 					::SetWindowPos(m_hWndPane[m_nSinglePane], NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
839 				else
840 					pT->InvalidateRect(&rect);
841 			}
842 		}
843 	}
844 
GetSplitterBarRect(LPRECT lpRect)845 	bool GetSplitterBarRect(LPRECT lpRect) const
846 	{
847 		ATLASSERT(lpRect != NULL);
848 		if((m_nSinglePane != SPLIT_PANE_NONE) || (m_xySplitterPos == -1))
849 			return false;
850 
851 		if(m_bVertical)
852 		{
853 			lpRect->left = m_rcSplitter.left + m_xySplitterPos;
854 			lpRect->top = m_rcSplitter.top;
855 			lpRect->right = m_rcSplitter.left + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge;
856 			lpRect->bottom = m_rcSplitter.bottom;
857 		}
858 		else
859 		{
860 			lpRect->left = m_rcSplitter.left;
861 			lpRect->top = m_rcSplitter.top + m_xySplitterPos;
862 			lpRect->right = m_rcSplitter.right;
863 			lpRect->bottom = m_rcSplitter.top + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge;
864 		}
865 
866 		return true;
867 	}
868 
GetSplitterPaneRect(int nPane,LPRECT lpRect)869 	bool GetSplitterPaneRect(int nPane, LPRECT lpRect) const
870 	{
871 		ATLASSERT((nPane == SPLIT_PANE_LEFT) || (nPane == SPLIT_PANE_RIGHT));
872 		ATLASSERT(lpRect != NULL);
873 		bool bRet = true;
874 		if(m_nSinglePane != SPLIT_PANE_NONE)
875 		{
876 			if(nPane == m_nSinglePane)
877 				*lpRect = m_rcSplitter;
878 			else
879 				bRet = false;
880 		}
881 		else if(nPane == SPLIT_PANE_LEFT)
882 		{
883 			if(m_bVertical)
884 			{
885 				lpRect->left = m_rcSplitter.left;
886 				lpRect->top = m_rcSplitter.top;
887 				lpRect->right = m_rcSplitter.left + m_xySplitterPos;
888 				lpRect->bottom = m_rcSplitter.bottom;
889 			}
890 			else
891 			{
892 				lpRect->left = m_rcSplitter.left;
893 				lpRect->top = m_rcSplitter.top;
894 				lpRect->right = m_rcSplitter.right;
895 				lpRect->bottom = m_rcSplitter.top + m_xySplitterPos;
896 			}
897 		}
898 		else if(nPane == SPLIT_PANE_RIGHT)
899 		{
900 			if(m_bVertical)
901 			{
902 				lpRect->left = m_rcSplitter.left + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge;
903 				lpRect->top = m_rcSplitter.top;
904 				lpRect->right = m_rcSplitter.right;
905 				lpRect->bottom = m_rcSplitter.bottom;
906 			}
907 			else
908 			{
909 				lpRect->left = m_rcSplitter.left;
910 				lpRect->top = m_rcSplitter.top + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge;
911 				lpRect->right = m_rcSplitter.right;
912 				lpRect->bottom = m_rcSplitter.bottom;
913 			}
914 		}
915 		else
916 		{
917 			bRet = false;
918 		}
919 
920 		return bRet;
921 	}
922 
IsOverSplitterRect(int x,int y)923 	bool IsOverSplitterRect(int x, int y) const
924 	{
925 		// -1 == don't check
926 		return ((x == -1 || (x >= m_rcSplitter.left && x <= m_rcSplitter.right)) &&
927 			(y == -1 || (y >= m_rcSplitter.top && y <= m_rcSplitter.bottom)));
928 	}
929 
IsOverSplitterBar(int x,int y)930 	bool IsOverSplitterBar(int x, int y) const
931 	{
932 		if(m_nSinglePane != SPLIT_PANE_NONE)
933 			return false;
934 		if((m_xySplitterPos == -1) || !IsOverSplitterRect(x, y))
935 			return false;
936 		int xy = m_bVertical ? x : y;
937 		int xyOff = m_bVertical ? m_rcSplitter.left : m_rcSplitter.top;
938 
939 		return ((xy >= (xyOff + m_xySplitterPos)) && (xy < xyOff + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge));
940 	}
941 
DrawGhostBar()942 	void DrawGhostBar()
943 	{
944 		RECT rect = { 0 };
945 		if(GetSplitterBarRect(&rect))
946 		{
947 			// convert client to window coordinates
948 			T* pT = static_cast<T*>(this);
949 			RECT rcWnd = { 0 };
950 			pT->GetWindowRect(&rcWnd);
951 			::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rcWnd, 2);
952 			::OffsetRect(&rect, -rcWnd.left, -rcWnd.top);
953 
954 			// invert the brush pattern (looks just like frame window sizing)
955 			CWindowDC dc(pT->m_hWnd);
956 			CBrush brush = CDCHandle::GetHalftoneBrush();
957 			if(brush.m_hBrush != NULL)
958 			{
959 				CBrushHandle brushOld = dc.SelectBrush(brush);
960 				dc.PatBlt(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, PATINVERT);
961 				dc.SelectBrush(brushOld);
962 			}
963 		}
964 	}
965 
GetSystemSettings(bool bUpdate)966 	void GetSystemSettings(bool bUpdate)
967 	{
968 		if((m_dwExtendedStyle & SPLIT_FIXEDBARSIZE) == 0)
969 		{
970 #ifndef _WIN32_WCE
971 			m_cxySplitBar = ::GetSystemMetrics(m_bVertical ? SM_CXSIZEFRAME : SM_CYSIZEFRAME);
972 #else // CE specific
973 			m_cxySplitBar = 2 * ::GetSystemMetrics(m_bVertical ? SM_CXEDGE : SM_CYEDGE);
974 #endif // _WIN32_WCE
975 		}
976 
977 		T* pT = static_cast<T*>(this);
978 		if((pT->GetExStyle() & WS_EX_CLIENTEDGE) != 0)
979 		{
980 			m_cxyBarEdge = 2 * ::GetSystemMetrics(m_bVertical ? SM_CXEDGE : SM_CYEDGE);
981 			m_cxyMin = 0;
982 		}
983 		else
984 		{
985 			m_cxyBarEdge = 0;
986 			m_cxyMin = 2 * ::GetSystemMetrics(m_bVertical ? SM_CXEDGE : SM_CYEDGE);
987 		}
988 
989 #ifndef _WIN32_WCE
990 		::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &m_bFullDrag, 0);
991 #endif // !_WIN32_WCE
992 
993 		if(bUpdate)
994 			UpdateSplitterLayout();
995 	}
996 
IsProportional()997 	bool IsProportional() const
998 	{
999 		return ((m_dwExtendedStyle & SPLIT_PROPORTIONAL) != 0);
1000 	}
1001 
StoreProportionalPos()1002 	void StoreProportionalPos()
1003 	{
1004 		int cxyTotal = m_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge);
1005 		if(cxyTotal > 0)
1006 			m_nProportionalPos = ::MulDiv(m_xySplitterPos, m_nPropMax, cxyTotal);
1007 		else
1008 			m_nProportionalPos = 0;
1009 		ATLTRACE2(atlTraceUI, 0, _T("CSplitterImpl::StoreProportionalPos - %i\n"), m_nProportionalPos);
1010 	}
1011 
UpdateProportionalPos()1012 	void UpdateProportionalPos()
1013 	{
1014 		int cxyTotal = m_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge);
1015 		if(cxyTotal > 0)
1016 		{
1017 			int xyNewPos = ::MulDiv(m_nProportionalPos, cxyTotal, m_nPropMax);
1018 			m_bUpdateProportionalPos = false;
1019 			T* pT = static_cast<T*>(this);
1020 			pT->SetSplitterPos(xyNewPos, false);
1021 		}
1022 	}
1023 
IsRightAligned()1024 	bool IsRightAligned() const
1025 	{
1026 		return ((m_dwExtendedStyle & SPLIT_RIGHTALIGNED) != 0);
1027 	}
1028 
StoreRightAlignPos()1029 	void StoreRightAlignPos()
1030 	{
1031 		int cxyTotal = m_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge);
1032 		if(cxyTotal > 0)
1033 			m_nProportionalPos = cxyTotal - m_xySplitterPos;
1034 		else
1035 			m_nProportionalPos = 0;
1036 		ATLTRACE2(atlTraceUI, 0, _T("CSplitterImpl::StoreRightAlignPos - %i\n"), m_nProportionalPos);
1037 	}
1038 
UpdateRightAlignPos()1039 	void UpdateRightAlignPos()
1040 	{
1041 		int cxyTotal = m_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge);
1042 		if(cxyTotal > 0)
1043 		{
1044 			m_bUpdateProportionalPos = false;
1045 			T* pT = static_cast<T*>(this);
1046 			pT->SetSplitterPos(cxyTotal - m_nProportionalPos, false);
1047 		}
1048 	}
1049 
IsInteractive()1050 	bool IsInteractive() const
1051 	{
1052 		return ((m_dwExtendedStyle & SPLIT_NONINTERACTIVE) == 0);
1053 	}
1054 };
1055 
1056 
1057 ///////////////////////////////////////////////////////////////////////////////
1058 // CSplitterWindowImpl - Implements a splitter window
1059 
1060 template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
1061 class ATL_NO_VTABLE CSplitterWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CSplitterImpl< T >
1062 {
1063 public:
DECLARE_WND_CLASS_EX(NULL,CS_DBLCLKS,COLOR_WINDOW)1064 	DECLARE_WND_CLASS_EX(NULL, CS_DBLCLKS, COLOR_WINDOW)
1065 
1066 	CSplitterWindowImpl(bool bVertical = true) : CSplitterImpl< T >(bVertical)
1067 	{ }
1068 
SubclassWindow(HWND hWnd)1069 	BOOL SubclassWindow(HWND hWnd)
1070 	{
1071 #if (_MSC_VER >= 1300)
1072 		BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd);
1073 #else // !(_MSC_VER >= 1300)
1074 		typedef ATL::CWindowImpl< T, TBase, TWinTraits >   _baseClass;
1075 		BOOL bRet = _baseClass::SubclassWindow(hWnd);
1076 #endif // !(_MSC_VER >= 1300)
1077 		if(bRet != FALSE)
1078 		{
1079 			T* pT = static_cast<T*>(this);
1080 			pT->Init();
1081 
1082 			SetSplitterRect();
1083 		}
1084 
1085 		return bRet;
1086 	}
1087 
1088 	BEGIN_MSG_MAP(CSplitterWindowImpl)
MESSAGE_HANDLER(WM_ERASEBKGND,OnEraseBackground)1089 		MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
1090 		MESSAGE_HANDLER(WM_SIZE, OnSize)
1091 		CHAIN_MSG_MAP(CSplitterImpl< T >)
1092 		FORWARD_NOTIFICATIONS()
1093 	END_MSG_MAP()
1094 
1095 	LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
1096 	{
1097 		// handled, no background painting needed
1098 		return 1;
1099 	}
1100 
OnSize(UINT,WPARAM wParam,LPARAM,BOOL & bHandled)1101 	LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
1102 	{
1103 		if(wParam != SIZE_MINIMIZED)
1104 			SetSplitterRect();
1105 
1106 		bHandled = FALSE;
1107 		return 1;
1108 	}
1109 };
1110 
1111 
1112 ///////////////////////////////////////////////////////////////////////////////
1113 // CSplitterWindow/CHorSplitterWindow - Implements splitter windows to be used as is
1114 
1115 template <bool t_bVertical = true>
1116 class CSplitterWindowT : public CSplitterWindowImpl<CSplitterWindowT<t_bVertical> >
1117 {
1118 public:
1119 	DECLARE_WND_CLASS_EX(_T("WTL_SplitterWindow"), CS_DBLCLKS, COLOR_WINDOW)
1120 
CSplitterWindowT()1121 	CSplitterWindowT() : CSplitterWindowImpl<CSplitterWindowT<t_bVertical> >(t_bVertical)
1122 	{ }
1123 };
1124 
1125 typedef CSplitterWindowT<true>    CSplitterWindow;
1126 typedef CSplitterWindowT<false>   CHorSplitterWindow;
1127 
1128 }; // namespace WTL
1129 
1130 #endif // __ATLSPLIT_H__
1131