OLD | NEW |
| (Empty) |
1 // Windows Template Library - WTL version 8.0 | |
2 // Copyright (C) Microsoft Corporation. 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 Permissive License (Ms-PL) which can be found in the file | |
7 // Ms-PL.txt at the root of this distribution. | |
8 | |
9 #ifndef __ATLSPLIT_H__ | |
10 #define __ATLSPLIT_H__ | |
11 | |
12 #pragma once | |
13 | |
14 #ifndef __cplusplus | |
15 #error ATL requires C++ compilation (use a .cpp suffix) | |
16 #endif | |
17 | |
18 #ifndef __ATLAPP_H__ | |
19 #error atlsplit.h requires atlapp.h to be included first | |
20 #endif | |
21 | |
22 #ifndef __ATLWIN_H__ | |
23 #error atlsplit.h requires atlwin.h to be included first | |
24 #endif | |
25 | |
26 | |
27 /////////////////////////////////////////////////////////////////////////////// | |
28 // Classes in this file: | |
29 // | |
30 // CSplitterImpl<T, t_bVertical> | |
31 // CSplitterWindowImpl<T, t_bVertical, TBase, TWinTraits> | |
32 // CSplitterWindowT<t_bVertical> | |
33 | |
34 | |
35 namespace WTL | |
36 { | |
37 | |
38 /////////////////////////////////////////////////////////////////////////////// | |
39 // CSplitterImpl - Provides splitter support to any window | |
40 | |
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 | |
47 | |
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 | |
53 | |
54 // Note: SPLIT_PROPORTIONAL and SPLIT_RIGHTALIGNED/SPLIT_BOTTOMALIGNED are | |
55 // mutually exclusive. If both are set, splitter defaults to SPLIT_PROPORTIONAL | |
56 | |
57 | |
58 template <class T, bool t_bVertical = true> | |
59 class CSplitterImpl | |
60 { | |
61 public: | |
62 enum { m_nPanesCount = 2, m_nPropMax = 10000 }; | |
63 | |
64 HWND m_hWndPane[m_nPanesCount]; | |
65 RECT m_rcSplitter; | |
66 int m_xySplitterPos; | |
67 int m_nDefActivePane; | |
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 | |
72 bool m_bFullDrag; | |
73 int m_cxyDragOffset; | |
74 int m_nProportionalPos; | |
75 bool m_bUpdateProportionalPos; | |
76 DWORD m_dwExtendedStyle; // splitter specific extended styles | |
77 int m_nSinglePane; // single pane mode | |
78 | |
79 // Constructor | |
80 CSplitterImpl() : | |
81 m_xySplitterPos(-1), m_nDefActivePane(SPLIT_PANE_NONE), | |
82 m_cxySplitBar(0), m_cxyMin(0), m_cxyBarEdge(0), m_bFullD
rag(true), | |
83 m_cxyDragOffset(0), m_nProportionalPos(0), m_bUpdateProp
ortionalPos(true), | |
84 m_dwExtendedStyle(SPLIT_PROPORTIONAL), | |
85 m_nSinglePane(SPLIT_PANE_NONE) | |
86 { | |
87 m_hWndPane[SPLIT_PANE_LEFT] = NULL; | |
88 m_hWndPane[SPLIT_PANE_RIGHT] = NULL; | |
89 | |
90 ::SetRectEmpty(&m_rcSplitter); | |
91 | |
92 if(m_hCursor == NULL) | |
93 { | |
94 CStaticDataInitCriticalSectionLock lock; | |
95 if(FAILED(lock.Lock())) | |
96 { | |
97 ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to l
ock critical section in CSplitterImpl::CSplitterImpl.\n")); | |
98 ATLASSERT(FALSE); | |
99 return; | |
100 } | |
101 | |
102 if(m_hCursor == NULL) | |
103 m_hCursor = ::LoadCursor(NULL, t_bVertical ? IDC
_SIZEWE : IDC_SIZENS); | |
104 | |
105 lock.Unlock(); | |
106 } | |
107 } | |
108 | |
109 // Attributes | |
110 void SetSplitterRect(LPRECT lpRect = NULL, bool bUpdate = true) | |
111 { | |
112 if(lpRect == NULL) | |
113 { | |
114 T* pT = static_cast<T*>(this); | |
115 pT->GetClientRect(&m_rcSplitter); | |
116 } | |
117 else | |
118 { | |
119 m_rcSplitter = *lpRect; | |
120 } | |
121 | |
122 if(IsProportional()) | |
123 UpdateProportionalPos(); | |
124 else if(IsRightAligned()) | |
125 UpdateRightAlignPos(); | |
126 | |
127 if(bUpdate) | |
128 UpdateSplitterLayout(); | |
129 } | |
130 | |
131 void GetSplitterRect(LPRECT lpRect) const | |
132 { | |
133 ATLASSERT(lpRect != NULL); | |
134 *lpRect = m_rcSplitter; | |
135 } | |
136 | |
137 bool SetSplitterPos(int xyPos = -1, bool bUpdate = true) | |
138 { | |
139 if(xyPos == -1) // -1 == middle | |
140 { | |
141 if(t_bVertical) | |
142 xyPos = (m_rcSplitter.right - m_rcSplitter.left
- m_cxySplitBar - m_cxyBarEdge) / 2; | |
143 else | |
144 xyPos = (m_rcSplitter.bottom - m_rcSplitter.top
- m_cxySplitBar - m_cxyBarEdge) / 2; | |
145 } | |
146 | |
147 // Adjust if out of valid range | |
148 int cxyMax = 0; | |
149 if(t_bVertical) | |
150 cxyMax = m_rcSplitter.right - m_rcSplitter.left; | |
151 else | |
152 cxyMax = m_rcSplitter.bottom - m_rcSplitter.top; | |
153 | |
154 if(xyPos < m_cxyMin + m_cxyBarEdge) | |
155 xyPos = m_cxyMin; | |
156 else if(xyPos > (cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMi
n)) | |
157 xyPos = cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin
; | |
158 | |
159 // Set new position and update if requested | |
160 bool bRet = (m_xySplitterPos != xyPos); | |
161 m_xySplitterPos = xyPos; | |
162 | |
163 if(m_bUpdateProportionalPos) | |
164 { | |
165 if(IsProportional()) | |
166 StoreProportionalPos(); | |
167 else if(IsRightAligned()) | |
168 StoreRightAlignPos(); | |
169 } | |
170 else | |
171 { | |
172 m_bUpdateProportionalPos = true; | |
173 } | |
174 | |
175 if(bUpdate && bRet) | |
176 UpdateSplitterLayout(); | |
177 | |
178 return bRet; | |
179 } | |
180 | |
181 void SetSplitterPosPct(int nPct, bool bUpdate = true) | |
182 { | |
183 ATLASSERT(nPct >= 0 && nPct <= 100); | |
184 | |
185 m_nProportionalPos = ::MulDiv(nPct, m_nPropMax, 100); | |
186 UpdateProportionalPos(); | |
187 | |
188 if(bUpdate) | |
189 UpdateSplitterLayout(); | |
190 } | |
191 | |
192 int GetSplitterPos() const | |
193 { | |
194 return m_xySplitterPos; | |
195 } | |
196 | |
197 bool SetSinglePaneMode(int nPane = SPLIT_PANE_NONE) | |
198 { | |
199 ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT
|| nPane == SPLIT_PANE_NONE); | |
200 if(!(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT || nP
ane == SPLIT_PANE_NONE)) | |
201 return false; | |
202 | |
203 if(nPane != SPLIT_PANE_NONE) | |
204 { | |
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; | |
211 } | |
212 else if(m_nSinglePane != SPLIT_PANE_NONE) | |
213 { | |
214 int nOtherPane = (m_nSinglePane == SPLIT_PANE_LEFT) ? SP
LIT_PANE_RIGHT : SPLIT_PANE_LEFT; | |
215 ::ShowWindow(m_hWndPane[nOtherPane], SW_SHOW); | |
216 } | |
217 | |
218 m_nSinglePane = nPane; | |
219 UpdateSplitterLayout(); | |
220 return true; | |
221 } | |
222 | |
223 int GetSinglePaneMode() const | |
224 { | |
225 return m_nSinglePane; | |
226 } | |
227 | |
228 DWORD GetSplitterExtendedStyle() const | |
229 { | |
230 return m_dwExtendedStyle; | |
231 } | |
232 | |
233 DWORD SetSplitterExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) | |
234 { | |
235 DWORD dwPrevStyle = m_dwExtendedStyle; | |
236 if(dwMask == 0) | |
237 m_dwExtendedStyle = dwExtendedStyle; | |
238 else | |
239 m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwE
xtendedStyle & dwMask); | |
240 #ifdef _DEBUG | |
241 if(IsProportional() && IsRightAligned()) | |
242 ATLTRACE2(atlTraceUI, 0, _T("CSplitterImpl::SetSplitterE
xtendedStyle - SPLIT_PROPORTIONAL and SPLIT_RIGHTALIGNED are mutually exclusive,
defaulting to SPLIT_PROPORTIONAL.\n")); | |
243 #endif // _DEBUG | |
244 return dwPrevStyle; | |
245 } | |
246 | |
247 // Splitter operations | |
248 void SetSplitterPanes(HWND hWndLeftTop, HWND hWndRightBottom, bool bUpda
te = true) | |
249 { | |
250 m_hWndPane[SPLIT_PANE_LEFT] = hWndLeftTop; | |
251 m_hWndPane[SPLIT_PANE_RIGHT] = hWndRightBottom; | |
252 ATLASSERT(m_hWndPane[SPLIT_PANE_LEFT] == NULL || m_hWndPane[SPLI
T_PANE_RIGHT] == NULL || m_hWndPane[SPLIT_PANE_LEFT] != m_hWndPane[SPLIT_PANE_RI
GHT]); | |
253 if(bUpdate) | |
254 UpdateSplitterLayout(); | |
255 } | |
256 | |
257 bool SetSplitterPane(int nPane, HWND hWnd, bool bUpdate = true) | |
258 { | |
259 ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT)
; | |
260 | |
261 if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT) | |
262 return false; | |
263 m_hWndPane[nPane] = hWnd; | |
264 ATLASSERT(m_hWndPane[SPLIT_PANE_LEFT] == NULL || m_hWndPane[SPLI
T_PANE_RIGHT] == NULL || m_hWndPane[SPLIT_PANE_LEFT] != m_hWndPane[SPLIT_PANE_RI
GHT]); | |
265 if(bUpdate) | |
266 UpdateSplitterLayout(); | |
267 return true; | |
268 } | |
269 | |
270 HWND GetSplitterPane(int nPane) const | |
271 { | |
272 ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT)
; | |
273 | |
274 if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT) | |
275 return false; | |
276 return m_hWndPane[nPane]; | |
277 } | |
278 | |
279 bool SetActivePane(int nPane) | |
280 { | |
281 ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT)
; | |
282 | |
283 if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT) | |
284 return false; | |
285 if(m_nSinglePane != SPLIT_PANE_NONE && nPane != m_nSinglePane) | |
286 return false; | |
287 ::SetFocus(m_hWndPane[nPane]); | |
288 m_nDefActivePane = nPane; | |
289 return true; | |
290 } | |
291 | |
292 int GetActivePane() const | |
293 { | |
294 int nRet = SPLIT_PANE_NONE; | |
295 HWND hWndFocus = ::GetFocus(); | |
296 if(hWndFocus != NULL) | |
297 { | |
298 for(int nPane = 0; nPane < m_nPanesCount; nPane++) | |
299 { | |
300 if(hWndFocus == m_hWndPane[nPane] || ::IsChild(m
_hWndPane[nPane], hWndFocus)) | |
301 { | |
302 nRet = nPane; | |
303 break; | |
304 } | |
305 } | |
306 } | |
307 return nRet; | |
308 } | |
309 | |
310 bool ActivateNextPane(bool bNext = true) | |
311 { | |
312 int nPane = m_nSinglePane; | |
313 if(nPane == SPLIT_PANE_NONE) | |
314 { | |
315 switch(GetActivePane()) | |
316 { | |
317 case SPLIT_PANE_LEFT: | |
318 nPane = SPLIT_PANE_RIGHT; | |
319 break; | |
320 case SPLIT_PANE_RIGHT: | |
321 nPane = SPLIT_PANE_LEFT; | |
322 break; | |
323 default: | |
324 nPane = bNext ? SPLIT_PANE_LEFT : SPLIT_PANE_RIG
HT; | |
325 break; | |
326 } | |
327 } | |
328 return SetActivePane(nPane); | |
329 } | |
330 | |
331 bool SetDefaultActivePane(int nPane) | |
332 { | |
333 ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT)
; | |
334 | |
335 if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT) | |
336 return false; | |
337 m_nDefActivePane = nPane; | |
338 return true; | |
339 } | |
340 | |
341 bool SetDefaultActivePane(HWND hWnd) | |
342 { | |
343 for(int nPane = 0; nPane < m_nPanesCount; nPane++) | |
344 { | |
345 if(hWnd == m_hWndPane[nPane]) | |
346 { | |
347 m_nDefActivePane = nPane; | |
348 return true; | |
349 } | |
350 } | |
351 return false; // not found | |
352 } | |
353 | |
354 int GetDefaultActivePane() const | |
355 { | |
356 return m_nDefActivePane; | |
357 } | |
358 | |
359 void DrawSplitter(CDCHandle dc) | |
360 { | |
361 ATLASSERT(dc.m_hDC != NULL); | |
362 if(m_nSinglePane == SPLIT_PANE_NONE && m_xySplitterPos == -1) | |
363 return; | |
364 | |
365 T* pT = static_cast<T*>(this); | |
366 if(m_nSinglePane == SPLIT_PANE_NONE) | |
367 { | |
368 pT->DrawSplitterBar(dc); | |
369 | |
370 for(int nPane = 0; nPane < m_nPanesCount; nPane++) | |
371 { | |
372 if(m_hWndPane[nPane] == NULL) | |
373 pT->DrawSplitterPane(dc, nPane); | |
374 } | |
375 } | |
376 else | |
377 { | |
378 if(m_hWndPane[m_nSinglePane] == NULL) | |
379 pT->DrawSplitterPane(dc, m_nSinglePane); | |
380 } | |
381 } | |
382 | |
383 // Overrideables | |
384 void DrawSplitterBar(CDCHandle dc) | |
385 { | |
386 RECT rect; | |
387 if(GetSplitterBarRect(&rect)) | |
388 { | |
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 ? (B
F_LEFT | BF_RIGHT) : (BF_TOP | BF_BOTTOM)); | |
394 } | |
395 } | |
396 | |
397 // called only if pane is empty | |
398 void DrawSplitterPane(CDCHandle dc, int nPane) | |
399 { | |
400 RECT rect; | |
401 if(GetSplitterPaneRect(nPane, &rect)) | |
402 { | |
403 T* pT = static_cast<T*>(this); | |
404 if((pT->GetExStyle() & WS_EX_CLIENTEDGE) == 0) | |
405 dc.DrawEdge(&rect, EDGE_SUNKEN, BF_RECT | BF_ADJ
UST); | |
406 dc.FillRect(&rect, COLOR_APPWORKSPACE); | |
407 } | |
408 } | |
409 | |
410 // Message map and handlers | |
411 BEGIN_MSG_MAP(CSplitterImpl) | |
412 MESSAGE_HANDLER(WM_CREATE, OnCreate) | |
413 MESSAGE_HANDLER(WM_PAINT, OnPaint) | |
414 #ifndef _WIN32_WCE | |
415 MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) | |
416 #endif // !_WIN32_WCE | |
417 if(IsInteractive()) | |
418 { | |
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) | |
425 } | |
426 MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) | |
427 #ifndef _WIN32_WCE | |
428 MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate) | |
429 #endif // !_WIN32_WCE | |
430 MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange) | |
431 END_MSG_MAP() | |
432 | |
433 LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BO
OL& bHandled) | |
434 { | |
435 GetSystemSettings(false); | |
436 bHandled = FALSE; | |
437 return 1; | |
438 } | |
439 | |
440 LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOO
L& /*bHandled*/) | |
441 { | |
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(); | |
446 // do painting | |
447 CPaintDC dc(pT->m_hWnd); | |
448 pT->DrawSplitter(dc.m_hDC); | |
449 return 0; | |
450 } | |
451 | |
452 LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& b
Handled) | |
453 { | |
454 T* pT = static_cast<T*>(this); | |
455 if((HWND)wParam == pT->m_hWnd && LOWORD(lParam) == HTCLIENT) | |
456 { | |
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)) | |
461 return 1; | |
462 } | |
463 | |
464 bHandled = FALSE; | |
465 return 0; | |
466 } | |
467 | |
468 LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& b
Handled) | |
469 { | |
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) | |
474 { | |
475 int xyNewSplitPos = 0; | |
476 if(t_bVertical) | |
477 xyNewSplitPos = xPos - m_rcSplitter.left - m_cxy
DragOffset; | |
478 else | |
479 xyNewSplitPos = yPos - m_rcSplitter.top - m_cxyD
ragOffset; | |
480 | |
481 if(xyNewSplitPos == -1) // avoid -1, that means middle | |
482 xyNewSplitPos = -2; | |
483 | |
484 if(m_xySplitterPos != xyNewSplitPos) | |
485 { | |
486 if(m_bFullDrag) | |
487 { | |
488 if(pT->SetSplitterPos(xyNewSplitPos, tru
e)) | |
489 pT->UpdateWindow(); | |
490 } | |
491 else | |
492 { | |
493 DrawGhostBar(); | |
494 pT->SetSplitterPos(xyNewSplitPos, false)
; | |
495 DrawGhostBar(); | |
496 } | |
497 } | |
498 } | |
499 else // not dragging, just set cursor | |
500 { | |
501 if(IsOverSplitterBar(xPos, yPos)) | |
502 ::SetCursor(m_hCursor); | |
503 bHandled = FALSE; | |
504 } | |
505 | |
506 return 0; | |
507 } | |
508 | |
509 LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, B
OOL& bHandled) | |
510 { | |
511 int xPos = GET_X_LPARAM(lParam); | |
512 int yPos = GET_Y_LPARAM(lParam); | |
513 if(IsOverSplitterBar(xPos, yPos)) | |
514 { | |
515 T* pT = static_cast<T*>(this); | |
516 pT->SetCapture(); | |
517 ::SetCursor(m_hCursor); | |
518 if(!m_bFullDrag) | |
519 DrawGhostBar(); | |
520 if(t_bVertical) | |
521 m_cxyDragOffset = xPos - m_rcSplitter.left - m_x
ySplitterPos; | |
522 else | |
523 m_cxyDragOffset = yPos - m_rcSplitter.top - m_xy
SplitterPos; | |
524 } | |
525 bHandled = FALSE; | |
526 return 1; | |
527 } | |
528 | |
529 LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/,
BOOL& bHandled) | |
530 { | |
531 ::ReleaseCapture(); | |
532 bHandled = FALSE; | |
533 return 1; | |
534 } | |
535 | |
536 LRESULT OnLButtonDoubleClick(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*
lParam*/, BOOL& /*bHandled*/) | |
537 { | |
538 T* pT = static_cast<T*>(this); | |
539 pT->SetSplitterPos(); // middle | |
540 return 0; | |
541 } | |
542 | |
543 LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lPar
am*/, BOOL& /*bHandled*/) | |
544 { | |
545 if(!m_bFullDrag) | |
546 { | |
547 DrawGhostBar(); | |
548 UpdateSplitterLayout(); | |
549 T* pT = static_cast<T*>(this); | |
550 pT->UpdateWindow(); | |
551 } | |
552 return 0; | |
553 } | |
554 | |
555 LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM, BOOL& bHand
led) | |
556 { | |
557 if(m_nSinglePane == SPLIT_PANE_NONE) | |
558 { | |
559 if(m_nDefActivePane == SPLIT_PANE_LEFT || m_nDefActivePa
ne == SPLIT_PANE_RIGHT) | |
560 ::SetFocus(m_hWndPane[m_nDefActivePane]); | |
561 } | |
562 else | |
563 { | |
564 ::SetFocus(m_hWndPane[m_nSinglePane]); | |
565 } | |
566 bHandled = FALSE; | |
567 return 1; | |
568 } | |
569 | |
570 #ifndef _WIN32_WCE | |
571 LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /
*bHandled*/) | |
572 { | |
573 T* pT = static_cast<T*>(this); | |
574 LRESULT lRet = pT->DefWindowProc(uMsg, wParam, lParam); | |
575 if(lRet == MA_ACTIVATE || lRet == MA_ACTIVATEANDEAT) | |
576 { | |
577 DWORD dwPos = ::GetMessagePos(); | |
578 POINT pt = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) }; | |
579 pT->ScreenToClient(&pt); | |
580 RECT rcPane; | |
581 for(int nPane = 0; nPane < m_nPanesCount; nPane++) | |
582 { | |
583 if(GetSplitterPaneRect(nPane, &rcPane) && ::PtIn
Rect(&rcPane, pt)) | |
584 { | |
585 m_nDefActivePane = nPane; | |
586 break; | |
587 } | |
588 } | |
589 } | |
590 return lRet; | |
591 } | |
592 #endif // !_WIN32_WCE | |
593 | |
594 LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lPara
m*/, BOOL& /*bHandled*/) | |
595 { | |
596 GetSystemSettings(true); | |
597 return 0; | |
598 } | |
599 | |
600 // Implementation - internal helpers | |
601 void UpdateSplitterLayout() | |
602 { | |
603 if(m_nSinglePane == SPLIT_PANE_NONE && m_xySplitterPos == -1) | |
604 return; | |
605 | |
606 T* pT = static_cast<T*>(this); | |
607 RECT rect = { 0, 0, 0, 0 }; | |
608 if(m_nSinglePane == SPLIT_PANE_NONE) | |
609 { | |
610 if(GetSplitterBarRect(&rect)) | |
611 pT->InvalidateRect(&rect); | |
612 | |
613 for(int nPane = 0; nPane < m_nPanesCount; nPane++) | |
614 { | |
615 if(GetSplitterPaneRect(nPane, &rect)) | |
616 { | |
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); | |
619 else | |
620 pT->InvalidateRect(&rect); | |
621 } | |
622 } | |
623 } | |
624 else | |
625 { | |
626 if(GetSplitterPaneRect(m_nSinglePane, &rect)) | |
627 { | |
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); | |
630 else | |
631 pT->InvalidateRect(&rect); | |
632 } | |
633 } | |
634 } | |
635 | |
636 bool GetSplitterBarRect(LPRECT lpRect) const | |
637 { | |
638 ATLASSERT(lpRect != NULL); | |
639 if(m_nSinglePane != SPLIT_PANE_NONE || m_xySplitterPos == -1) | |
640 return false; | |
641 | |
642 if(t_bVertical) | |
643 { | |
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; | |
648 } | |
649 else | |
650 { | |
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; | |
655 } | |
656 | |
657 return true; | |
658 } | |
659 | |
660 bool GetSplitterPaneRect(int nPane, LPRECT lpRect) const | |
661 { | |
662 ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT)
; | |
663 ATLASSERT(lpRect != NULL); | |
664 bool bRet = true; | |
665 if(m_nSinglePane != SPLIT_PANE_NONE) | |
666 { | |
667 if(nPane == m_nSinglePane) | |
668 *lpRect = m_rcSplitter; | |
669 else | |
670 bRet = false; | |
671 } | |
672 else if(nPane == SPLIT_PANE_LEFT) | |
673 { | |
674 if(t_bVertical) | |
675 { | |
676 lpRect->left = m_rcSplitter.left; | |
677 lpRect->top = m_rcSplitter.top; | |
678 lpRect->right = m_rcSplitter.left + m_xySplitter
Pos; | |
679 lpRect->bottom = m_rcSplitter.bottom; | |
680 } | |
681 else | |
682 { | |
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_xySplitter
Pos; | |
687 } | |
688 } | |
689 else if(nPane == SPLIT_PANE_RIGHT) | |
690 { | |
691 if(t_bVertical) | |
692 { | |
693 lpRect->left = m_rcSplitter.left + m_xySplitterP
os + m_cxySplitBar + m_cxyBarEdge; | |
694 lpRect->top = m_rcSplitter.top; | |
695 lpRect->right = m_rcSplitter.right; | |
696 lpRect->bottom = m_rcSplitter.bottom; | |
697 } | |
698 else | |
699 { | |
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; | |
704 } | |
705 } | |
706 else | |
707 { | |
708 bRet = false; | |
709 } | |
710 return bRet; | |
711 } | |
712 | |
713 bool IsOverSplitterRect(int x, int y) const | |
714 { | |
715 // -1 == don't check | |
716 return ((x == -1 || (x >= m_rcSplitter.left && x <= m_rcSplitter
.right)) && | |
717 (y == -1 || (y >= m_rcSplitter.top && y <= m_rcSplitter.
bottom))); | |
718 } | |
719 | |
720 bool IsOverSplitterBar(int x, int y) const | |
721 { | |
722 if(m_nSinglePane != SPLIT_PANE_NONE) | |
723 return false; | |
724 if(m_xySplitterPos == -1 || !IsOverSplitterRect(x, y)) | |
725 return false; | |
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_xyS
plitterPos + m_cxySplitBar + m_cxyBarEdge)); | |
729 } | |
730 | |
731 void DrawGhostBar() | |
732 { | |
733 RECT rect = { 0, 0, 0, 0 }; | |
734 if(GetSplitterBarRect(&rect)) | |
735 { | |
736 // invert the brush pattern (looks just like frame windo
w 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) | |
741 { | |
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); | |
745 } | |
746 } | |
747 } | |
748 | |
749 void GetSystemSettings(bool bUpdate) | |
750 { | |
751 #ifndef _WIN32_WCE | |
752 m_cxySplitBar = ::GetSystemMetrics(t_bVertical ? SM_CXSIZEFRAME
: SM_CYSIZEFRAME); | |
753 #else // CE specific | |
754 m_cxySplitBar = 2 * ::GetSystemMetrics(t_bVertical ? SM_CXEDGE :
SM_CYEDGE); | |
755 #endif // _WIN32_WCE | |
756 | |
757 T* pT = static_cast<T*>(this); | |
758 if((pT->GetExStyle() & WS_EX_CLIENTEDGE)) | |
759 { | |
760 m_cxyBarEdge = 2 * ::GetSystemMetrics(t_bVertical ? SM_C
XEDGE : SM_CYEDGE); | |
761 m_cxyMin = 0; | |
762 } | |
763 else | |
764 { | |
765 m_cxyBarEdge = 0; | |
766 m_cxyMin = 2 * ::GetSystemMetrics(t_bVertical ? SM_CXEDG
E : SM_CYEDGE); | |
767 } | |
768 | |
769 #ifndef _WIN32_WCE | |
770 ::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &m_bFullDrag,
0); | |
771 #endif // !_WIN32_WCE | |
772 | |
773 if(bUpdate) | |
774 UpdateSplitterLayout(); | |
775 } | |
776 | |
777 bool IsProportional() const | |
778 { | |
779 return ((m_dwExtendedStyle & SPLIT_PROPORTIONAL) != 0); | |
780 } | |
781 | |
782 void StoreProportionalPos() | |
783 { | |
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); | |
785 if(cxyTotal > 0) | |
786 m_nProportionalPos = ::MulDiv(m_xySplitterPos, m_nPropMa
x, cxyTotal); | |
787 else | |
788 m_nProportionalPos = 0; | |
789 ATLTRACE2(atlTraceUI, 0, _T("CSplitterImpl::StoreProportionalPos
- %i\n"), m_nProportionalPos); | |
790 } | |
791 | |
792 void UpdateProportionalPos() | |
793 { | |
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); | |
795 if(cxyTotal > 0) | |
796 { | |
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); | |
801 } | |
802 } | |
803 | |
804 bool IsRightAligned() const | |
805 { | |
806 return ((m_dwExtendedStyle & SPLIT_RIGHTALIGNED) != 0); | |
807 } | |
808 | |
809 void StoreRightAlignPos() | |
810 { | |
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); | |
812 if(cxyTotal > 0) | |
813 m_nProportionalPos = cxyTotal - m_xySplitterPos; | |
814 else | |
815 m_nProportionalPos = 0; | |
816 ATLTRACE2(atlTraceUI, 0, _T("CSplitterImpl::StoreRightAlignPos -
%i\n"), m_nProportionalPos); | |
817 } | |
818 | |
819 void UpdateRightAlignPos() | |
820 { | |
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); | |
822 if(cxyTotal > 0) | |
823 { | |
824 m_bUpdateProportionalPos = false; | |
825 T* pT = static_cast<T*>(this); | |
826 pT->SetSplitterPos(cxyTotal - m_nProportionalPos, false)
; | |
827 } | |
828 } | |
829 | |
830 bool IsInteractive() const | |
831 { | |
832 return ((m_dwExtendedStyle & SPLIT_NONINTERACTIVE) == 0); | |
833 } | |
834 }; | |
835 | |
836 template <class T, bool t_bVertical> HCURSOR CSplitterImpl< T, t_bVertical>::m_h
Cursor = NULL; | |
837 | |
838 | |
839 /////////////////////////////////////////////////////////////////////////////// | |
840 // CSplitterWindowImpl - Implements a splitter window | |
841 | |
842 template <class T, bool t_bVertical = true, class TBase = ATL::CWindow, class TW
inTraits = ATL::CControlWinTraits> | |
843 class ATL_NO_VTABLE CSplitterWindowImpl : public ATL::CWindowImpl< T, TBase, TWi
nTraits >, public CSplitterImpl< T , t_bVertical > | |
844 { | |
845 public: | |
846 DECLARE_WND_CLASS_EX(NULL, CS_DBLCLKS, COLOR_WINDOW) | |
847 | |
848 typedef CSplitterImpl< T , t_bVertical > _baseClass; | |
849 | |
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() | |
855 END_MSG_MAP() | |
856 | |
857 LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lPa
ram*/, BOOL& /*bHandled*/) | |
858 { | |
859 // handled, no background painting needed | |
860 return 1; | |
861 } | |
862 | |
863 LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bH
andled) | |
864 { | |
865 if(wParam != SIZE_MINIMIZED) | |
866 SetSplitterRect(); | |
867 | |
868 bHandled = FALSE; | |
869 return 1; | |
870 } | |
871 }; | |
872 | |
873 | |
874 /////////////////////////////////////////////////////////////////////////////// | |
875 // CSplitterWindow - Implements a splitter window to be used as is | |
876 | |
877 template <bool t_bVertical = true> | |
878 class CSplitterWindowT : public CSplitterWindowImpl<CSplitterWindowT<t_bVertical
>, t_bVertical> | |
879 { | |
880 public: | |
881 DECLARE_WND_CLASS_EX(_T("WTL_SplitterWindow"), CS_DBLCLKS, COLOR_WINDOW) | |
882 }; | |
883 | |
884 typedef CSplitterWindowT<true> CSplitterWindow; | |
885 typedef CSplitterWindowT<false> CHorSplitterWindow; | |
886 | |
887 }; // namespace WTL | |
888 | |
889 #endif // __ATLSPLIT_H__ | |
OLD | NEW |