Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / third_party / wtl / include / atlsplit.h
blob9f9424b22535b06e7866b4f33d9e0241f89c5ef9
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.
9 #ifndef __ATLSPLIT_H__
10 #define __ATLSPLIT_H__
12 #pragma once
14 #ifndef __cplusplus
15 #error ATL requires C++ compilation (use a .cpp suffix)
16 #endif
18 #ifndef __ATLAPP_H__
19 #error atlsplit.h requires atlapp.h to be included first
20 #endif
22 #ifndef __ATLWIN_H__
23 #error atlsplit.h requires atlwin.h to be included first
24 #endif
27 ///////////////////////////////////////////////////////////////////////////////
28 // Classes in this file:
30 // CSplitterImpl<T, t_bVertical>
31 // CSplitterWindowImpl<T, t_bVertical, TBase, TWinTraits>
32 // CSplitterWindowT<t_bVertical>
35 namespace WTL
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>
59 class CSplitterImpl
61 public:
62 enum { m_nPanesCount = 2, m_nPropMax = 10000 };
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
79 // Constructor
80 CSplitterImpl() :
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);
92 if(m_hCursor == NULL)
94 CStaticDataInitCriticalSectionLock lock;
95 if(FAILED(lock.Lock()))
97 ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CSplitterImpl::CSplitterImpl.\n"));
98 ATLASSERT(FALSE);
99 return;
102 if(m_hCursor == NULL)
103 m_hCursor = ::LoadCursor(NULL, t_bVertical ? IDC_SIZEWE : IDC_SIZENS);
105 lock.Unlock();
109 // Attributes
110 void SetSplitterRect(LPRECT lpRect = NULL, bool bUpdate = true)
112 if(lpRect == NULL)
114 T* pT = static_cast<T*>(this);
115 pT->GetClientRect(&m_rcSplitter);
117 else
119 m_rcSplitter = *lpRect;
122 if(IsProportional())
123 UpdateProportionalPos();
124 else if(IsRightAligned())
125 UpdateRightAlignPos();
127 if(bUpdate)
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
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;
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;
154 if(xyPos < m_cxyMin + m_cxyBarEdge)
155 xyPos = m_cxyMin;
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)
165 if(IsProportional())
166 StoreProportionalPos();
167 else if(IsRightAligned())
168 StoreRightAlignPos();
170 else
172 m_bUpdateProportionalPos = true;
175 if(bUpdate && bRet)
176 UpdateSplitterLayout();
178 return bRet;
181 void SetSplitterPosPct(int nPct, bool bUpdate = true)
183 ATLASSERT(nPct >= 0 && nPct <= 100);
185 m_nProportionalPos = ::MulDiv(nPct, m_nPropMax, 100);
186 UpdateProportionalPos();
188 if(bUpdate)
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))
201 return false;
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();
220 return true;
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;
236 if(dwMask == 0)
237 m_dwExtendedStyle = dwExtendedStyle;
238 else
239 m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);
240 #ifdef _DEBUG
241 if(IsProportional() && IsRightAligned())
242 ATLTRACE2(atlTraceUI, 0, _T("CSplitterImpl::SetSplitterExtendedStyle - SPLIT_PROPORTIONAL and SPLIT_RIGHTALIGNED are mutually exclusive, defaulting to SPLIT_PROPORTIONAL.\n"));
243 #endif // _DEBUG
244 return dwPrevStyle;
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]);
253 if(bUpdate)
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)
262 return false;
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]);
265 if(bUpdate)
266 UpdateSplitterLayout();
267 return true;
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)
275 return false;
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)
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;
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))
302 nRet = nPane;
303 break;
307 return nRet;
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;
319 break;
320 case SPLIT_PANE_RIGHT:
321 nPane = SPLIT_PANE_LEFT;
322 break;
323 default:
324 nPane = bNext ? SPLIT_PANE_LEFT : SPLIT_PANE_RIGHT;
325 break;
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)
336 return false;
337 m_nDefActivePane = nPane;
338 return true;
341 bool SetDefaultActivePane(HWND hWnd)
343 for(int nPane = 0; nPane < m_nPanesCount; nPane++)
345 if(hWnd == m_hWndPane[nPane])
347 m_nDefActivePane = nPane;
348 return true;
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)
363 return;
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);
376 else
378 if(m_hWndPane[m_nSinglePane] == NULL)
379 pT->DrawSplitterPane(dc, m_nSinglePane);
383 // Overrideables
384 void DrawSplitterBar(CDCHandle dc)
386 RECT rect;
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)
400 RECT rect;
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)
414 #ifndef _WIN32_WCE
415 MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
416 #endif // !_WIN32_WCE
417 if(IsInteractive())
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)
427 #ifndef _WIN32_WCE
428 MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate)
429 #endif // !_WIN32_WCE
430 MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)
431 END_MSG_MAP()
433 LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
435 GetSystemSettings(false);
436 bHandled = FALSE;
437 return 1;
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();
446 // do painting
447 CPaintDC dc(pT->m_hWnd);
448 pT->DrawSplitter(dc.m_hDC);
449 return 0;
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))
461 return 1;
464 bHandled = FALSE;
465 return 0;
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;
476 if(t_bVertical)
477 xyNewSplitPos = xPos - m_rcSplitter.left - m_cxyDragOffset;
478 else
479 xyNewSplitPos = yPos - m_rcSplitter.top - m_cxyDragOffset;
481 if(xyNewSplitPos == -1) // avoid -1, that means middle
482 xyNewSplitPos = -2;
484 if(m_xySplitterPos != xyNewSplitPos)
486 if(m_bFullDrag)
488 if(pT->SetSplitterPos(xyNewSplitPos, true))
489 pT->UpdateWindow();
491 else
493 DrawGhostBar();
494 pT->SetSplitterPos(xyNewSplitPos, false);
495 DrawGhostBar();
499 else // not dragging, just set cursor
501 if(IsOverSplitterBar(xPos, yPos))
502 ::SetCursor(m_hCursor);
503 bHandled = FALSE;
506 return 0;
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);
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_xySplitterPos;
522 else
523 m_cxyDragOffset = yPos - m_rcSplitter.top - m_xySplitterPos;
525 bHandled = FALSE;
526 return 1;
529 LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
531 ::ReleaseCapture();
532 bHandled = FALSE;
533 return 1;
536 LRESULT OnLButtonDoubleClick(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
538 T* pT = static_cast<T*>(this);
539 pT->SetSplitterPos(); // middle
540 return 0;
543 LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
545 if(!m_bFullDrag)
547 DrawGhostBar();
548 UpdateSplitterLayout();
549 T* pT = static_cast<T*>(this);
550 pT->UpdateWindow();
552 return 0;
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]);
562 else
564 ::SetFocus(m_hWndPane[m_nSinglePane]);
566 bHandled = FALSE;
567 return 1;
570 #ifndef _WIN32_WCE
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);
580 RECT rcPane;
581 for(int nPane = 0; nPane < m_nPanesCount; nPane++)
583 if(GetSplitterPaneRect(nPane, &rcPane) && ::PtInRect(&rcPane, pt))
585 m_nDefActivePane = nPane;
586 break;
590 return lRet;
592 #endif // !_WIN32_WCE
594 LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
596 GetSystemSettings(true);
597 return 0;
600 // Implementation - internal helpers
601 void UpdateSplitterLayout()
603 if(m_nSinglePane == SPLIT_PANE_NONE && m_xySplitterPos == -1)
604 return;
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);
619 else
620 pT->InvalidateRect(&rect);
624 else
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);
630 else
631 pT->InvalidateRect(&rect);
636 bool GetSplitterBarRect(LPRECT lpRect) const
638 ATLASSERT(lpRect != NULL);
639 if(m_nSinglePane != SPLIT_PANE_NONE || m_xySplitterPos == -1)
640 return false;
642 if(t_bVertical)
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;
649 else
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;
657 return true;
660 bool GetSplitterPaneRect(int nPane, LPRECT lpRect) const
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)
667 if(nPane == m_nSinglePane)
668 *lpRect = m_rcSplitter;
669 else
670 bRet = false;
672 else if(nPane == SPLIT_PANE_LEFT)
674 if(t_bVertical)
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;
681 else
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)
691 if(t_bVertical)
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;
698 else
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;
706 else
708 bRet = false;
710 return bRet;
713 bool IsOverSplitterRect(int x, int y) const
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)));
720 bool IsOverSplitterBar(int x, int y) const
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_xySplitterPos + m_cxySplitBar + m_cxyBarEdge));
731 void DrawGhostBar()
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)
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
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);
761 m_cxyMin = 0;
763 else
765 m_cxyBarEdge = 0;
766 m_cxyMin = 2 * ::GetSystemMetrics(t_bVertical ? SM_CXEDGE : SM_CYEDGE);
769 #ifndef _WIN32_WCE
770 ::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &m_bFullDrag, 0);
771 #endif // !_WIN32_WCE
773 if(bUpdate)
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);
785 if(cxyTotal > 0)
786 m_nProportionalPos = ::MulDiv(m_xySplitterPos, m_nPropMax, cxyTotal);
787 else
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);
795 if(cxyTotal > 0)
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);
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);
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);
822 if(cxyTotal > 0)
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 >
845 public:
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()
855 END_MSG_MAP()
857 LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
859 // handled, no background painting needed
860 return 1;
863 LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
865 if(wParam != SIZE_MINIMIZED)
866 SetSplitterRect();
868 bHandled = FALSE;
869 return 1;
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>
880 public:
881 DECLARE_WND_CLASS_EX(_T("WTL_SplitterWindow"), CS_DBLCLKS, COLOR_WINDOW)
884 typedef CSplitterWindowT<true> CSplitterWindow;
885 typedef CSplitterWindowT<false> CHorSplitterWindow;
887 }; // namespace WTL
889 #endif // __ATLSPLIT_H__